Example #1
0
int getNextShape(mapObj *map, layerObj *layer, float *values, styleObj **styles, shapeObj *shape) {
    int status;
    int c;
    status = msLayerNextShape(layer, shape);
    if(status == MS_SUCCESS) {
#ifdef USE_PROJ
        if(layer->project && msProjectionsDiffer(&(layer->projection), &(map->projection)))
            msProjectShape(&layer->projection, &map->projection, shape);
        else
            layer->project = MS_FALSE;
#endif

        if(msBindLayerToShape(layer, shape, MS_FALSE) != MS_SUCCESS)
            return MS_FAILURE; /* error message is set in msBindLayerToShape() */

        for(c=0; c<layer->numclasses; c++)
        {
            values[c]=(layer->class[c]->styles[0]->size);
            styles[c]=layer->class[c]->styles[0];
        }
    }
    return status;
}
Example #2
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);
      }
    }
Example #3
0
char *FLTGetSpatialComparisonCommonExpression(FilterEncodingNode *psNode, layerObj *lp)
{
  char *pszExpression = NULL;
  shapeObj *psQueryShape = NULL;
  double dfDistance = -1;
  int nUnit = -1, nLayerUnit = -1;
  char *pszWktText = NULL;
  char szBuffer[256];
  char *pszTmp=NULL;
  projectionObj sProjTmp;
  rectObj sQueryRect;
  shapeObj *psTmpShape=NULL;
  int bBBoxQuery = 0;
  int bAlreadyReprojected = 0;

  if (psNode == NULL || lp == NULL)
    return NULL;

  if (psNode->eType != FILTER_NODE_TYPE_SPATIAL)
    return NULL;

  /* get the shape */
  if (FLTIsBBoxFilter(psNode)) {
    char szPolygon[512];
    FLTGetBBOX(psNode, &sQueryRect);

    snprintf(szPolygon, sizeof(szPolygon),
             "POLYGON((%.18f %.18f,%.18f %.18f,%.18f %.18f,%.18f %.18f,%.18f %.18f))",
             sQueryRect.minx, sQueryRect.miny,
             sQueryRect.minx, sQueryRect.maxy,
             sQueryRect.maxx, sQueryRect.maxy,
             sQueryRect.maxx, sQueryRect.miny,
             sQueryRect.minx, sQueryRect.miny);

    psTmpShape = msShapeFromWKT(szPolygon);

    /* 
    ** This is a horrible hack to deal with world-extent requests and
    ** reprojection. msProjectRect() detects if reprojection from longlat to 
    ** projected SRS, and in that case it transforms the bbox to -1e-15,-1e-15,1e15,1e15
    ** to ensure that all features are returned.
    **
    ** Make wfs_200_cite_filter_bbox_world.xml and wfs_200_cite_postgis_bbox_world.xml pass
    */
    if (fabs(sQueryRect.minx - -180.0) < 1e-5 &&
        fabs(sQueryRect.miny - -90.0) < 1e-5 &&
        fabs(sQueryRect.maxx - 180.0) < 1e-5 &&
        fabs(sQueryRect.maxy - 90.0) < 1e-5)
    {
      if (lp->projection.numargs > 0) {
        if (psNode->pszSRS)
          msInitProjection(&sProjTmp);
        if (psNode->pszSRS) {
          /* Use the non EPSG variant since axis swapping is done in FLTDoAxisSwappingIfNecessary */
          if (msLoadProjectionString(&sProjTmp, psNode->pszSRS) == 0) {
            msProjectRect(&sProjTmp, &lp->projection, &sQueryRect);
          }
        } else if (lp->map->projection.numargs > 0)
          msProjectRect(&lp->map->projection, &lp->projection, &sQueryRect);
        if (psNode->pszSRS)
          msFreeProjection(&sProjTmp);
      }
      if (sQueryRect.minx <= -1e14) {
        msFreeShape(psTmpShape);
        msFree(psTmpShape);
        psTmpShape = (shapeObj*) msSmallMalloc(sizeof(shapeObj));
        msInitShape(psTmpShape);
        msRectToPolygon(sQueryRect, psTmpShape);
        bAlreadyReprojected = 1;
      }
    }

    bBBoxQuery = 1;
  } else {
    /* other geos type operations */

    /* project shape to layer projection. If the proj is not part of the filter query,
      assume that the cooredinates are in the map projection */

    psQueryShape = FLTGetShape(psNode, &dfDistance, &nUnit);

    if ((strcasecmp(psNode->pszValue, "DWithin") == 0 || strcasecmp(psNode->pszValue, "Beyond") == 0 ) && dfDistance > 0) {
      nLayerUnit = lp->units;
      if(nLayerUnit == -1) nLayerUnit = GetMapserverUnitUsingProj(&lp->projection);
      if(nLayerUnit == -1) nLayerUnit = lp->map->units;
      if(nLayerUnit == -1) nLayerUnit = GetMapserverUnitUsingProj(&lp->map->projection);

      if (nUnit >= 0 && nUnit != nLayerUnit)
        dfDistance *= msInchesPerUnit(nUnit,0)/msInchesPerUnit(nLayerUnit,0); /* target is layer units */
    }

    psTmpShape = psQueryShape;
  }

  if (psTmpShape) {

    /*
    ** target is layer projection
    */
    if (!bAlreadyReprojected && lp->projection.numargs > 0) {
      if (psNode->pszSRS)
        msInitProjection(&sProjTmp);
      if (psNode->pszSRS) {
        /* Use the non EPSG variant since axis swapping is done in FLTDoAxisSwappingIfNecessary */
        if (msLoadProjectionString(&sProjTmp, psNode->pszSRS) == 0) {
          msProjectShape(&sProjTmp, &lp->projection, psTmpShape);
        }
      } else if (lp->map->projection.numargs > 0)
        msProjectShape(&lp->map->projection, &lp->projection, psTmpShape);
      if (psNode->pszSRS)
        msFreeProjection(&sProjTmp);
    }

    /* function name */
    if (bBBoxQuery) {
      sprintf(szBuffer, "%s", "intersects");
    } else {
      if (strncasecmp(psNode->pszValue, "intersect", 9) == 0)
        sprintf(szBuffer, "%s", "intersects");
      else {
        pszTmp = msStrdup(psNode->pszValue);
        msStringToLower(pszTmp);
        sprintf(szBuffer, "%s", pszTmp);
        msFree(pszTmp);
      }
    }
    pszExpression = msStringConcatenate(pszExpression, szBuffer);
    pszExpression = msStringConcatenate(pszExpression, "(");

    /* geometry binding */
    sprintf(szBuffer, "%s", "[shape]");
    pszExpression = msStringConcatenate(pszExpression, szBuffer);
    pszExpression = msStringConcatenate(pszExpression, ",");

    /* filter geometry */
    pszWktText = msGEOSShapeToWKT(psTmpShape);
    sprintf(szBuffer, "%s", "fromText('");
    pszExpression = msStringConcatenate(pszExpression, szBuffer);
    pszExpression = msStringConcatenate(pszExpression, pszWktText);
    sprintf(szBuffer, "%s", "')");
    pszExpression = msStringConcatenate(pszExpression, szBuffer);
    msGEOSFreeWKT(pszWktText);

    /* (optional) beyond/dwithin distance, always 0.0 since we apply the distance as a buffer earlier */
    if ((strcasecmp(psNode->pszValue, "DWithin") == 0 || strcasecmp(psNode->pszValue, "Beyond") == 0)) {
      // pszExpression = msStringConcatenate(pszExpression, ",0.0");
      sprintf(szBuffer, ",%g", dfDistance);
      pszExpression = msStringConcatenate(pszExpression, szBuffer);      
    }

    /* terminate the function */
    pszExpression = msStringConcatenate(pszExpression, ") = TRUE");
  }

  /*
  ** Cleanup
  */
  if (bBBoxQuery) {
    msFreeShape(psTmpShape);
    msFree(psTmpShape);
  }

  return pszExpression;
}
char *FLTGetSpatialComparisonCommonExpression(FilterEncodingNode *psNode, layerObj *lp)
{
    char *pszExpression = NULL;
    shapeObj *psQueryShape = NULL;
    double dfDistance = -1;
    int nUnit = -1;
    char *pszWktText = NULL;
    char szBuffer[256];
    char *pszTmp=NULL;
    projectionObj sProjTmp;
    char *pszEPSG= NULL;
    rectObj sQueryRect;
    shapeObj *psTmpShape=NULL, *psBufferShape=NULL;
    int bBBoxQuery = 0;
    
    if (psNode == NULL || lp == NULL)
      return NULL;

    if (psNode->eType != FILTER_NODE_TYPE_SPATIAL)
      return NULL;

    /* get the shape*/
    /*BBOX case: replace it with NOT DISJOINT.*/
    if(FLTIsBBoxFilter(psNode))
    {
        pszEPSG = FLTGetBBOX(psNode, &sQueryRect);
        /*this should be removed and bbox should parse and strore the srs properly, 
          using now legacy code*/
        if (pszEPSG)
          psNode->pszSRS = msStrdup(pszEPSG);
        
        psTmpShape = (shapeObj *)msSmallMalloc(sizeof(shapeObj));
        msInitShape(psTmpShape);
        msRectToPolygon(sQueryRect, psTmpShape);
        bBBoxQuery = 1;

    }
    else
    {
        /*other geos type operations*/

        /*project shape to layer projection. If the proj is not part of the filter query,
          assume that the cooredinates are in the map projection*/
      
        psQueryShape = FLTGetShape(psNode, &dfDistance, &nUnit);
    
        if ((strcasecmp(psNode->pszValue, "DWithin") == 0 ||
             strcasecmp(psNode->pszValue, "Beyond") == 0 ) &&
            dfDistance > 0)
        {
            if (nUnit >=0 && nUnit != lp->map->units)
              dfDistance *= msInchesPerUnit(nUnit,0)/msInchesPerUnit(lp->map->units,0);

            psBufferShape = msGEOSBuffer(psQueryShape, dfDistance);
        }
        if (psBufferShape)
          psTmpShape = psBufferShape;
        else
          psTmpShape = psQueryShape;
    }

    if (psTmpShape)
    {
        if( lp->projection.numargs > 0)
        {
            if (psNode->pszSRS && FTLParseEpsgString(psNode->pszSRS, &sProjTmp))
            {
              msProjectShape(&sProjTmp, &lp->projection, psTmpShape);
              msFreeProjection(&sProjTmp);
            }
            else if (lp->map->projection.numargs > 0)
              msProjectShape(&lp->map->projection, &lp->projection, psTmpShape);
        }
/* ==================================================================== */
/*      use within for bbox. Not Disjoint does not work.                */
/* ==================================================================== */
        if (bBBoxQuery)
          sprintf(szBuffer, "%s", " ([shape] ");
        /* sprintf(szBuffer, "%s", " (NOT ([shape] "); */
        else
          sprintf(szBuffer, "%s", " ([shape] ");

        pszExpression = msStringConcatenate(pszExpression, szBuffer);


        if (strncasecmp(psNode->pszValue, "intersect", 9) == 0)
          pszTmp = msStrdup("intersects");
        else
          pszTmp = msStrdup(psNode->pszValue);
        msStringToLower(pszTmp);
        if (bBBoxQuery)
          sprintf(szBuffer, " %s ", "intersects");
        /* sprintf(szBuffer, " %s ", "disjoint"); */
        else
           sprintf(szBuffer, " %s ", pszTmp);

        pszExpression = msStringConcatenate(pszExpression, szBuffer);
        msFree(pszTmp);

        pszWktText = msGEOSShapeToWKT(psTmpShape);
        sprintf(szBuffer, "%s", " fromText('");
        pszExpression = msStringConcatenate(pszExpression, szBuffer);
        pszExpression = msStringConcatenate(pszExpression, pszWktText);
        sprintf(szBuffer, "%s", "')");
        pszExpression = msStringConcatenate(pszExpression, szBuffer);
        msGEOSFreeWKT(pszWktText);
    }
    if (psBufferShape)
      msFreeShape(psBufferShape);

    
    sprintf(szBuffer, "%s", ")");
    pszExpression = msStringConcatenate(pszExpression, szBuffer);

    if (0) /* bBBoxQuery */
     {
          sprintf(szBuffer, "%s", ")");
          pszExpression = msStringConcatenate(pszExpression, szBuffer);
     }
    return pszExpression;
}