Ejemplo n.º 1
0
/* rebuild the clusters according to the current extent */
int RebuildClusters(layerObj *layer, int isQuery)
{
  mapObj* map;
  layerObj* srcLayer;
  double distance, maxDistanceX, maxDistanceY, cellSizeX, cellSizeY;
  rectObj searchrect;
  int status;
  clusterInfo* current;
  int depth;
#ifdef USE_CLUSTER_EXTERNAL
  int layerIndex;
#endif

  msClusterLayerInfo* layerinfo = layer->layerinfo;

  if (!layerinfo) {
    msSetError(MS_MISCERR, "Layer is not open: %s", "RebuildClusters()", layer->name);
    return MS_FAILURE;
  }

  if (!layer->map) {
    msSetError(MS_MISCERR, "No map associated with this layer: %s", "RebuildClusters()", layer->name);
    return MS_FAILURE;
  }

  if (layer->debug >= MS_DEBUGLEVEL_VVV)
    msDebug("Clustering started.\n");

  map = layer->map;

  layerinfo->current = layerinfo->finalized; /* restart */

  /* check whether all shapes should be returned from a query */
  if(msLayerGetProcessingKey(layer, "CLUSTER_GET_ALL_SHAPES") != NULL)
    layerinfo->get_all_shapes = MS_TRUE;
  else
    layerinfo->get_all_shapes = MS_FALSE;

  /* identify the current extent */
  if(layer->transform == MS_TRUE)
    searchrect = map->extent;
  else {
    searchrect.minx = searchrect.miny = 0;
    searchrect.maxx = map->width-1;
    searchrect.maxy = map->height-1;
  }

  if (searchrect.minx == layerinfo->searchRect.minx &&
      searchrect.miny == layerinfo->searchRect.miny &&
      searchrect.maxx == layerinfo->searchRect.maxx &&
      searchrect.maxy == layerinfo->searchRect.maxy) {
    /* already built */
    return MS_SUCCESS;
  }

  /* destroy previous data*/
  clusterDestroyData(layerinfo);

  layerinfo->searchRect = searchrect;

  /* reproject the rectangle to layer coordinates */
#ifdef USE_PROJ
  if((map->projection.numargs > 0) && (layer->projection.numargs > 0))
    msProjectRect(&map->projection, &layer->projection, &searchrect); /* project the searchrect to source coords */
#endif

  /* determine the compare method */
  layerinfo->fnCompare = CompareRectangleRegion;
  if (layer->cluster.region) {
    if (EQUAL(layer->cluster.region, "ellipse"))
      layerinfo->fnCompare = CompareEllipseRegion;
  }

  /* trying to find a reasonable quadtree depth */
  depth = 0;
  distance = layer->cluster.maxdistance;
  while ((distance < map->width || distance < map->height) && depth <= TREE_MAX_DEPTH) {
    distance *= 2;
    ++depth;
  }

  layerinfo->depth = depth;

  cellSizeX = MS_CELLSIZE(searchrect.minx, searchrect.maxx, map->width);
  cellSizeY = MS_CELLSIZE(searchrect.miny, searchrect.maxy, map->height);

  maxDistanceX = layer->cluster.maxdistance * cellSizeX;
  maxDistanceY = layer->cluster.maxdistance * cellSizeY;

  /* increase the search rectangle so that the neighbouring shapes are also retrieved */
  searchrect.minx -= layer->cluster.buffer * cellSizeX;
  searchrect.maxx += layer->cluster.buffer * cellSizeX;
  searchrect.miny -= layer->cluster.buffer * cellSizeY;
  searchrect.maxy += layer->cluster.buffer * cellSizeY;

  /* create the root node */
  if (layerinfo->root)
    clusterTreeNodeDestroy(layerinfo, layerinfo->root);
  layerinfo->root = clusterTreeNodeCreate(layerinfo, searchrect);

  srcLayer = &layerinfo->srcLayer;

  /* start retrieving the shapes */
  status = msLayerWhichShapes(srcLayer, searchrect, isQuery);
  if(status == MS_DONE) {
    /* no overlap */
    return MS_SUCCESS;
  } else if(status != MS_SUCCESS) {
    return MS_FAILURE;
  }

  /* step through the source shapes and populate the quadtree with the tentative clusters */
  if ((current = clusterInfoCreate(layerinfo)) == NULL)
    return MS_FAILURE;

  while((status = msLayerNextShape(srcLayer, &current->shape)) == MS_SUCCESS) {
#if defined(USE_PROJ) && defined(USE_CLUSTER_EXTERNAL)
    /* transform the shape to the projection of this layer */
    if(srcLayer->transform == MS_TRUE && srcLayer->project && layer->transform == MS_TRUE && layer->project &&msProjectionsDiffer(&(srcLayer->projection), &(layer->projection)))
      msProjectShape(&srcLayer->projection, &layer->projection, &current->shape);
#endif
    /* set up positions and variance */
    current->avgx = current->x = current->shape.bounds.minx;
    current->avgy = current->y = current->shape.bounds.miny;
    current->varx = current->vary = 0;
    /* set up the area of interest when searching for the neighboring shapes */
    current->bounds.minx = current->x - maxDistanceX;
    current->bounds.miny = current->y - maxDistanceY;
    current->bounds.maxx = current->x + maxDistanceX;
    current->bounds.maxy = current->y + maxDistanceY;

    /* if the shape doesn't overlap we must skip it to avoid further issues */
    if(!msRectOverlap(&searchrect, &current->bounds)) {
      msFreeShape(&current->shape);
      msInitShape(&current->shape);

      msDebug("Skipping an invalid shape falling outside of the given extent\n");
      continue;
    }

    /* construct the item array */
    if (layer->iteminfo)
      BuildFeatureAttributes(layer, layerinfo, &current->shape);

    /* evaluate the group expression */
    if (layer->cluster.group.string)
      current->group = msClusterGetGroupText(&layer->cluster.group, &current->shape);

    /*start a query for the related shapes */
    findRelatedShapes(layerinfo, layerinfo->root, current);

    /* add this shape to the tree */
    if (treeNodeAddShape(layerinfo, layerinfo->root, current, depth) != MS_SUCCESS) {
      clusterInfoDestroyList(layerinfo, current);
      return MS_FAILURE;
    }

    if ((current = clusterInfoCreate(layerinfo)) == NULL) {
      clusterInfoDestroyList(layerinfo, current);
      return MS_FAILURE;
    }
  }

  clusterInfoDestroyList(layerinfo, current);

  while (layerinfo->root) {
#ifdef TESTCOUNT
    int n;
    double avgx, avgy;
#endif

    /* pick up the best cluster from the tree and do the finalization */
    /* the initial rank must be big enough */
    layerinfo->rank = (searchrect.maxx - searchrect.minx) * (searchrect.maxx - searchrect.minx) +
                      (searchrect.maxy - searchrect.miny) * (searchrect.maxy - searchrect.miny) + 1;

    layerinfo->current = NULL;
    findBestCluster(layer, layerinfo, layerinfo->root);

    if (layerinfo->current == NULL) {
      if (layer->debug >= MS_DEBUGLEVEL_VVV)
        msDebug("Clustering terminated.\n");
      break; /* completed */
    }

    /* Update the feature count of the shape */
    InitShapeAttributes(layer, layerinfo->current);

    /* collecting the shapes of the cluster */
    collectClusterShapes(layerinfo, layerinfo->root, layerinfo->current);

    if (layer->debug >= MS_DEBUGLEVEL_VVV) {
      msDebug("processing cluster %p: rank=%lf fcount=%d ncoll=%d nfin=%d nfins=%d nflt=%d bounds={%lf %lf %lf %lf}\n", layerinfo->current, layerinfo->rank, layerinfo->current->numsiblings + 1,
              layerinfo->current->numcollected, layerinfo->numFinalized, layerinfo->numFinalizedSiblings,
              layerinfo->numFiltered, layerinfo->current->bounds.minx, layerinfo->current->bounds.miny,
              layerinfo->current->bounds.maxx, layerinfo->current->bounds.maxy);
      if (layerinfo->current->node) {
        char pszBuffer[TREE_MAX_DEPTH + 1];
        clusterTreeNode* node = layerinfo->current->node;
        int position = node->position;
        int i = 1;
        while (position > 0 && i <= TREE_MAX_DEPTH) {
          pszBuffer[TREE_MAX_DEPTH - i] = '0' + (position % 4);
          position = position >> 2;
          ++i;
        }
        pszBuffer[TREE_MAX_DEPTH] = 0;

        msDebug(" ->node %p: count=%d index=%d pos=%s subn={%p %p %p %p} rect={%lf %lf %lf %lf}\n",
                node, node->numshapes, node->index, pszBuffer + TREE_MAX_DEPTH - i + 1,
                node->subnode[0], node->subnode[1], node->subnode[2], node->subnode[3],
                node->rect.minx, node->rect.miny, node->rect.maxx, node->rect.maxy);
      }
    }
Ejemplo n.º 2
0
int msUVRASTERLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery)
{
  uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *) layer->layerinfo;
  imageObj *image_tmp;
  outputFormatObj *outputformat = NULL;
  mapObj *map_tmp;
  double map_cellsize;
  unsigned int spacing;
  int width, height, u_src_off, v_src_off, i, x, y;
  char   **alteredProcessing = NULL, *saved_layer_mask;
  char **savedProcessing = NULL;

  
  if (layer->debug)
    msDebug("Entering msUVRASTERLayerWhichShapes().\n");

  if( uvlinfo == NULL )
    return MS_FAILURE;

  /* QUERY NOT SUPPORTED YET */
  if (isQuery == MS_TRUE) {
    msSetError( MS_MISCERR, "Query is not supported for UV layer.", "msUVRASTERLayerWhichShapes()" );
    return MS_FAILURE;
  }


  if( CSLFetchNameValue( layer->processing, "BANDS" ) == NULL ) {
    msSetError( MS_MISCERR, "BANDS processing option is required for UV layer. You have to specified 2 bands.",
                "msUVRASTERLayerWhichShapes()" );
    return MS_FAILURE;
  }
  
  /*
  ** Allocate mapObj structure
  */
  map_tmp = (mapObj *)msSmallCalloc(sizeof(mapObj),1);
  if(initMap(map_tmp) == -1) { /* initialize this map */
    msFree(map_tmp);
    return(MS_FAILURE);
  }

  /* -------------------------------------------------------------------- */
  /*      Determine desired spacing.  Default to 32 if not otherwise set  */
  /* -------------------------------------------------------------------- */
  spacing = 32;
  if( CSLFetchNameValue( layer->processing, "UV_SPACING" ) != NULL ) {
    spacing =
      atoi(CSLFetchNameValue( layer->processing, "UV_SPACING" ));
  }

  width = (int)ceil(layer->map->width/spacing);
  height = (int)ceil(layer->map->height/spacing);
  map_cellsize = MS_MAX(MS_CELLSIZE(rect.minx, rect.maxx,layer->map->width),
                        MS_CELLSIZE(rect.miny,rect.maxy,layer->map->height));
  map_tmp->cellsize = map_cellsize*spacing;
  
  if (layer->debug)
    msDebug("msUVRASTERLayerWhichShapes(): width: %d, height: %d, cellsize: %g\n",
            width, height, map_tmp->cellsize);

  /* Initialize our dummy map */
  MS_INIT_COLOR(map_tmp->imagecolor, 255,255,255,255);
  map_tmp->resolution = layer->map->resolution;
  map_tmp->defresolution = layer->map->defresolution;

  outputformat = (outputFormatObj *) msSmallCalloc(1,sizeof(outputFormatObj));
  outputformat->bands = uvlinfo->band_count = 2;
  outputformat->name = NULL;
  outputformat->driver = NULL;
  outputformat->refcount = 0;
  outputformat->vtable = NULL;
  outputformat->device = NULL;
  outputformat->renderer = MS_RENDER_WITH_RAWDATA;
  outputformat->imagemode = MS_IMAGEMODE_FLOAT32;
  msAppendOutputFormat(map_tmp, outputformat);
  
  msCopyHashTable(&map_tmp->configoptions, &layer->map->configoptions);
  map_tmp->mappath = msStrdup(layer->map->mappath);
  map_tmp->shapepath = msStrdup(layer->map->shapepath);
  map_tmp->extent.minx = rect.minx-(0.5*map_cellsize)+(0.5*map_tmp->cellsize);
  map_tmp->extent.miny = rect.miny-(0.5*map_cellsize)+(0.5*map_tmp->cellsize);
  map_tmp->extent.maxx = map_tmp->extent.minx+((width-1)*map_tmp->cellsize);
  map_tmp->extent.maxy = map_tmp->extent.miny+((height-1)*map_tmp->cellsize);
  map_tmp->gt.rotation_angle = 0.0;

   msCopyProjection(&map_tmp->projection, &layer->projection);

  if (layer->debug == 5)
    msDebug("msUVRASTERLayerWhichShapes(): extent: %g %g %g %g\n",
            map_tmp->extent.minx, map_tmp->extent.miny,
            map_tmp->extent.maxx, map_tmp->extent.maxy);

  /* important to use that function, to compute map
     geotransform, used by the resampling*/
   msMapSetSize(map_tmp, width, height);

  if (layer->debug == 5)
    msDebug("msUVRASTERLayerWhichShapes(): geotransform: %g %g %g %g %g %g\n",
            map_tmp->gt.geotransform[0], map_tmp->gt.geotransform[1],
            map_tmp->gt.geotransform[2], map_tmp->gt.geotransform[3],
            map_tmp->gt.geotransform[4], map_tmp->gt.geotransform[5]);

  uvlinfo->extent = map_tmp->extent;

  image_tmp = msImageCreate(width, height, map_tmp->outputformatlist[0],
                            NULL, NULL, map_tmp->resolution, map_tmp->defresolution,
                            &(map_tmp->imagecolor));

  /* Default set to AVERAGE resampling */
  if( CSLFetchNameValue( layer->processing, "RESAMPLE" ) == NULL ) {
    alteredProcessing = CSLDuplicate( layer->processing );
    alteredProcessing =
      CSLSetNameValue( alteredProcessing, "RESAMPLE",
                       "AVERAGE");
    savedProcessing = layer->processing;
    layer->processing = alteredProcessing;
  }

  /* disable masking at this level: we don't want to apply the mask at the raster level,
   * it will be applied with the correct cellsize and image size in the vector rendering
   * phase.
   */
  saved_layer_mask = layer->mask;
  layer->mask = NULL;
  if (msDrawRasterLayerLow(map_tmp, layer, image_tmp, NULL ) == MS_FAILURE) {
    msSetError(MS_MISCERR, "Unable to draw raster data.", "msUVRASTERLayerWhichShapes()");
    layer->mask = saved_layer_mask;
    return MS_FAILURE;
  }

  /* restore layer mask */
  layer->mask = saved_layer_mask;

  /* restore the saved processing */
  if (alteredProcessing != NULL) {
    layer->processing = savedProcessing;
    CSLDestroy(alteredProcessing);
  }

  /* free old query arrays */
  if (uvlinfo->u) {
    for (i=0; i<uvlinfo->width; ++i) {
      free(uvlinfo->u[i]);
    }
    free(uvlinfo->u);
  }

  if (uvlinfo->v) {
    for (i=0; i<uvlinfo->height; ++i) {
      free(uvlinfo->v[i]);
    }
    free(uvlinfo->v);
  }

  /* Update our uv layer structure */
  uvlinfo->width = width;
  uvlinfo->height = height;
  uvlinfo->query_results = width*height;

  uvlinfo->u = (float **)msSmallMalloc(sizeof(float *)*width);
  uvlinfo->v = (float **)msSmallMalloc(sizeof(float *)*width);

  for (x = 0; x < width; ++x) {
    uvlinfo->u[x] = (float *)msSmallMalloc(height * sizeof(float));
    uvlinfo->v[x] = (float *)msSmallMalloc(height * sizeof(float));

    for (y = 0; y < height; ++y) {
      u_src_off = v_src_off = x + y * width;
      v_src_off += width*height;

      uvlinfo->u[x][y] = image_tmp->img.raw_float[u_src_off];
      uvlinfo->v[x][y] = image_tmp->img.raw_float[v_src_off];

      /* null vector? update the number of results  */
      if (uvlinfo->u[x][y] == 0 && uvlinfo->v[x][y] == 0)
        --uvlinfo->query_results;
    }
  }

  msFreeImage(image_tmp); /* we do not need the imageObj anymore */
  msFreeMap(map_tmp);

  uvlinfo->next_shape = 0;

  return MS_SUCCESS;
}
Ejemplo n.º 3
0
static int msContourLayerReadRaster(layerObj *layer, rectObj rect)
{
  mapObj *map = layer->map;  
  char **bands;
  char pointer[64], memDSPointer[128];
  int band = 1;
  double adfGeoTransform[6], adfInvGeoTransform[6];
  double llx, lly, urx, ury;  
  rectObj copyRect, mapRect;
  int dst_xsize, dst_ysize;
  int virtual_grid_step_x, virtual_grid_step_y;
  int src_xoff, src_yoff, src_xsize, src_ysize;  
  double map_cellsize_x, map_cellsize_y, dst_cellsize_x, dst_cellsize_y;
  GDALRasterBandH hBand = NULL;
  CPLErr eErr;
  
  contourLayerInfo *clinfo = (contourLayerInfo *) layer->layerinfo;

  if (layer->debug)
    msDebug("Entering msContourLayerReadRaster().\n");

  if (clinfo == NULL || clinfo->hOrigDS == NULL) {
    msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!",
               "msContourLayerReadRaster()");
    return MS_FAILURE;    
  }

  bands = CSLTokenizeStringComplex(
               CSLFetchNameValue(layer->processing,"BANDS"), " ,", FALSE, FALSE );
  if (CSLCount(bands) > 0) {
    band = atoi(bands[0]);
    if (band < 1 || band > GDALGetRasterCount(clinfo->hOrigDS)) {
      msSetError( MS_IMGERR,
                  "BANDS PROCESSING directive includes illegal band '%d', should be from 1 to %d.",
                  "msContourLayerReadRaster()",
                  band, GDALGetRasterCount(clinfo->hOrigDS));
      CSLDestroy(bands);
      return MS_FAILURE;
    }
  }
  CSLDestroy(bands);

  hBand = GDALGetRasterBand(clinfo->hOrigDS, band);
  if (hBand == NULL)
  {
    msSetError(MS_IMGERR,
               "Band %d does not exist on dataset.",
               "msContourLayerReadRaster()", band);
    return MS_FAILURE;
  }

  if (layer->projection.numargs > 0 &&
      EQUAL(layer->projection.args[0], "auto")) {
    const char *wkt;
    wkt = GDALGetProjectionRef(clinfo->hOrigDS);
    if (wkt != NULL && strlen(wkt) > 0) {
      if (msOGCWKT2ProjectionObj(wkt, &(layer->projection),
                                 layer->debug) != MS_SUCCESS) {
        char  msg[MESSAGELENGTH*2];
        errorObj *ms_error = msGetErrorObj();

        snprintf( msg, sizeof(msg),
                  "%s\n"
                  "PROJECTION AUTO cannot be used for this "
                  "GDAL raster (`%s').",
                  ms_error->message, layer->data);
        msg[MESSAGELENGTH-1] = '\0';

        msSetError(MS_OGRERR, "%s","msDrawRasterLayer()",
                   msg);
        return MS_FAILURE;
      }
    }
  }
  
  /*
   * Compute the georeferenced window of overlap, and read the source data
   * downsampled to match output resolution, or at full resolution if
   * output resolution is lower than the source resolution.
   *
   * A large portion of this overlap calculation code was borrowed from 
   * msDrawRasterLayerGDAL(). 
   * Would be possible to move some of this to a reusable function?
   *
   * Note: This code works only if no reprojection is involved. It would
   * need rework to support cases where output projection differs from source
   * data file projection.
   */
  
  src_xsize = GDALGetRasterXSize(clinfo->hOrigDS);
  src_ysize = GDALGetRasterYSize(clinfo->hOrigDS);

  /* set the Dataset extent */
  msGetGDALGeoTransform(clinfo->hOrigDS, map, layer, adfGeoTransform);  
  clinfo->extent.minx = adfGeoTransform[0];
  clinfo->extent.maxy = adfGeoTransform[3];
  clinfo->extent.maxx = adfGeoTransform[0] + src_xsize * adfGeoTransform[1];
  clinfo->extent.miny = adfGeoTransform[3] + src_ysize * adfGeoTransform[5];
  
  if (layer->transform) {
    if (layer->debug)
      msDebug("msContourLayerReadRaster(): Entering transform.\n");

    InvGeoTransform(adfGeoTransform, adfInvGeoTransform);

    mapRect = rect;
    map_cellsize_x = map_cellsize_y = map->cellsize;      
#ifdef USE_PROJ
    /* if necessary, project the searchrect to source coords */
    if (msProjectionsDiffer( &(map->projection), &(layer->projection)))  {
      if ( msProjectRect(&map->projection, &layer->projection, &mapRect)
          != MS_SUCCESS ) {
        msDebug("msContourLayerReadRaster(%s): unable to reproject map request rectangle into layer projection, canceling.\n", layer->name);
        return MS_FAILURE;
      }

      map_cellsize_x = MS_CELLSIZE(mapRect.minx, mapRect.maxx, map->width);
      map_cellsize_y = MS_CELLSIZE(mapRect.miny, mapRect.maxy, map->height);

      /* if the projection failed to project the extent requested, we need to
         calculate the cellsize to preserve the initial map cellsize ratio */
      if ( (mapRect.minx < GEO_TRANS(adfGeoTransform,0,src_ysize)) ||
           (mapRect.maxx > GEO_TRANS(adfGeoTransform,src_xsize,0)) ||
           (mapRect.miny < GEO_TRANS(adfGeoTransform+3,0,src_ysize)) || 
           (mapRect.maxy > GEO_TRANS(adfGeoTransform+3,src_xsize,0)) ) {

        int src_unit, dst_unit;
        src_unit = GetMapserverUnitUsingProj(&map->projection);
        dst_unit = GetMapserverUnitUsingProj(&layer->projection);
        if (src_unit == -1 || dst_unit == -1) {
          msDebug("msContourLayerReadRaster(%s): unable to reproject map request rectangle into layer projection, canceling.\n", layer->name);
          return MS_FAILURE;
        }

        map_cellsize_x =  MS_CONVERT_UNIT(src_unit, dst_unit,
                                          MS_CELLSIZE(rect.minx, rect.maxx, map->width)); 
        map_cellsize_y = MS_CONVERT_UNIT(src_unit, dst_unit,
                                         MS_CELLSIZE(rect.miny, rect.maxy, map->height));
      }       
    }
#endif
    
    if (map_cellsize_x == 0 || map_cellsize_y == 0) {
      if (layer->debug)
        msDebug("msContourLayerReadRaster(): Cellsize can't be 0.\n");
      return MS_FAILURE;
    }
    
    /* Adjust MapServer pixel model to GDAL pixel model */
    mapRect.minx -= map_cellsize_x*0.5;
    mapRect.maxx += map_cellsize_x*0.5;
    mapRect.miny -= map_cellsize_y*0.5;
    mapRect.maxy += map_cellsize_y*0.5;


    /*
     * If raw data cellsize (from geotransform) is larger than output map_cellsize
     * then we want to extract only enough data to match the output map resolution
     * which means that GDAL will automatically sample the data on read.
     *
     * To prevent bad contour effects on tile edges, we adjust the target cellsize 
     * to align the extracted window with a virtual grid based on the origin of the 
     * raw data and a virtual grid step size corresponding to an integer sampling step.
     *
     * If source data has a greater cellsize (i.e. lower res) that requested ouptut map
     * then we use the raw data cellsize as target cellsize since there is no point in 
     * interpolating the data for contours in this case.
     */

    virtual_grid_step_x = (int)floor(map_cellsize_x / ABS(adfGeoTransform[1]));
    if (virtual_grid_step_x < 1)
      virtual_grid_step_x = 1; /* Do not interpolate data if grid sampling step < 1 */

    virtual_grid_step_y = (int)floor(map_cellsize_y / ABS(adfGeoTransform[5]));
    if (virtual_grid_step_y < 1)
      virtual_grid_step_y = 1; /* Do not interpolate data if grid sampling step < 1 */
    
    /* target cellsize is a multiple of raw data cellsize based on grid step*/
    dst_cellsize_x = ABS(adfGeoTransform[1]) * virtual_grid_step_x;
    dst_cellsize_y = ABS(adfGeoTransform[5]) * virtual_grid_step_y;

    /* Compute overlap between source and target views */

    copyRect = mapRect;

    if (copyRect.minx < GEO_TRANS(adfGeoTransform,0,src_ysize))
      copyRect.minx = GEO_TRANS(adfGeoTransform,0,src_ysize);
    if (copyRect.maxx > GEO_TRANS(adfGeoTransform,src_xsize,0))
      copyRect.maxx = GEO_TRANS(adfGeoTransform,src_xsize,0);
    if (copyRect.miny < GEO_TRANS(adfGeoTransform+3,0,src_ysize))
      copyRect.miny = GEO_TRANS(adfGeoTransform+3,0,src_ysize);
    if (copyRect.maxy > GEO_TRANS(adfGeoTransform+3,src_xsize,0))
      copyRect.maxy = GEO_TRANS(adfGeoTransform+3,src_xsize,0);
    
    if (copyRect.minx >= copyRect.maxx || copyRect.miny >= copyRect.maxy) {
      if (layer->debug)
        msDebug("msContourLayerReadRaster(): No overlap.\n");
      return MS_SUCCESS;
    }

    /*
     * Convert extraction window to raster coordinates
     */
    llx = GEO_TRANS(adfInvGeoTransform+0,copyRect.minx,copyRect.miny);
    lly = GEO_TRANS(adfInvGeoTransform+3,copyRect.minx,copyRect.miny);
    urx = GEO_TRANS(adfInvGeoTransform+0,copyRect.maxx,copyRect.maxy);
    ury = GEO_TRANS(adfInvGeoTransform+3,copyRect.maxx,copyRect.maxy);

    /* 
     * Align extraction window with virtual grid 
     * (keep in mind raster coordinates origin is at upper-left)
     * We also add an extra buffer to fix tile boundarie issues when zoomed
     */
    llx = floor(llx / virtual_grid_step_x) * virtual_grid_step_x - (virtual_grid_step_x*5);
    urx = ceil(urx / virtual_grid_step_x) * virtual_grid_step_x + (virtual_grid_step_x*5);
    ury = floor(ury / virtual_grid_step_y) * virtual_grid_step_y - (virtual_grid_step_x*5);
    lly = ceil(lly / virtual_grid_step_y) * virtual_grid_step_y + (virtual_grid_step_x*5);
    
    src_xoff = MAX(0,(int) floor(llx+0.5));
    src_yoff = MAX(0,(int) floor(ury+0.5));
    src_xsize = MIN(MAX(0,(int) (urx - llx + 0.5)),
                    GDALGetRasterXSize(clinfo->hOrigDS) - src_xoff);
    src_ysize = MIN(MAX(0,(int) (lly - ury + 0.5)),
                    GDALGetRasterYSize(clinfo->hOrigDS) - src_yoff);

    /* Update the geographic extent (buffer added) */
    /* TODO: a better way to go the geo_trans */
    copyRect.minx = GEO_TRANS(adfGeoTransform+0,src_xoff,0);
    copyRect.maxx = GEO_TRANS(adfGeoTransform+0,src_xoff+src_xsize,0);
    copyRect.miny = GEO_TRANS(adfGeoTransform+3,0,src_yoff+src_ysize);
    copyRect.maxy = GEO_TRANS(adfGeoTransform+3,0,src_yoff);
    
    /* 
     * If input window is to small then stop here
     */
    if (src_xsize < 2 || src_ysize < 2)
    {
      if (layer->debug)
        msDebug("msContourLayerReadRaster(): input window too small, or no apparent overlap between map view and this window(1).\n");
      return MS_SUCCESS;
    }

    /* Target buffer size */
    dst_xsize = (int)ceil((copyRect.maxx - copyRect.minx) / dst_cellsize_x);
    dst_ysize = (int)ceil((copyRect.maxy - copyRect.miny) / dst_cellsize_y);

    if (dst_xsize == 0 || dst_ysize == 0) {
      if (layer->debug)
        msDebug("msContourLayerReadRaster(): no apparent overlap between map view and this window(2).\n");
      return MS_SUCCESS;
    }

    if (layer->debug)
      msDebug( "msContourLayerReadRaster(): src=%d,%d,%d,%d, dst=%d,%d,%d,%d\n",
               src_xoff, src_yoff, src_xsize, src_ysize,
               0, 0, dst_xsize, dst_ysize );
  } else {
    src_xoff = 0;
    src_yoff = 0;
    dst_xsize = src_xsize = MIN(map->width,src_xsize);
    dst_ysize = src_ysize = MIN(map->height,src_ysize);
    copyRect.minx = copyRect.miny = 0;
    copyRect.maxx = map->width;
    copyRect.maxy = map->height;
    dst_cellsize_y = dst_cellsize_x = 1;
  }

  /* -------------------------------------------------------------------- */
  /*      Allocate buffer, and read data into it.                         */
  /* -------------------------------------------------------------------- */

  clinfo->buffer = (double *) malloc(sizeof(double) * dst_xsize * dst_ysize);
  if (clinfo->buffer == NULL) {
    msSetError(MS_MEMERR, "Malloc(): Out of memory.", "msContourLayerReadRaster()");
    return MS_FAILURE;
  }

  eErr = GDALRasterIO(hBand, GF_Read,
                      src_xoff, src_yoff, src_xsize, src_ysize,
                      clinfo->buffer, dst_xsize, dst_ysize, GDT_Float64,
                      0, 0);

  if (eErr != CE_None) {
    msSetError( MS_IOERR, "GDALRasterIO() failed: %s",
                "msContourLayerReadRaster()", CPLGetLastErrorMsg() );
    free(clinfo->buffer);
    return MS_FAILURE;
  }

  memset(pointer, 0, sizeof(pointer));
  CPLPrintPointer(pointer, clinfo->buffer, sizeof(pointer));
  sprintf(memDSPointer,"MEM:::DATAPOINTER=%s,PIXELS=%d,LINES=%d,BANDS=1,DATATYPE=Float64",
          pointer, dst_xsize, dst_ysize);
  clinfo->hDS = GDALOpen(memDSPointer,  GA_ReadOnly);
  if (clinfo->hDS == NULL) {
    msSetError(MS_IMGERR,
               "Unable to open GDAL Memory dataset.",
               "msContourLayerReadRaster()");
    free(clinfo->buffer);
    return MS_FAILURE;
  }

  adfGeoTransform[0] = copyRect.minx;
  adfGeoTransform[1] = dst_cellsize_x;
  adfGeoTransform[2] = 0;
  adfGeoTransform[3] = copyRect.maxy;
  adfGeoTransform[4] = 0;
  adfGeoTransform[5] = -dst_cellsize_y;

  clinfo->cellsize = MAX(dst_cellsize_x, dst_cellsize_y);
  {
    char buf[64];
    sprintf(buf, "%lf", clinfo->cellsize);
    msInsertHashTable(&layer->metadata, "__data_cellsize__", buf);
  }
      
  GDALSetGeoTransform(clinfo->hDS, adfGeoTransform);
  return MS_SUCCESS;
}