Skip to content

Commit 02d9b44

Browse files
committed
Clustering enhancements (#4822)
1 parent 1e6ef43 commit 02d9b44

File tree

1 file changed

+60
-11
lines changed

1 file changed

+60
-11
lines changed

mapcluster.c

+60-11
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,13 @@
4141
#endif
4242

4343
/* custom attributes provided by this layer data source */
44-
#define MSCLUSTER_NUMITEMS 2
44+
#define MSCLUSTER_NUMITEMS 3
4545
#define MSCLUSTER_FEATURECOUNT "Cluster:FeatureCount"
4646
#define MSCLUSTER_FEATURECOUNTINDEX -100
4747
#define MSCLUSTER_GROUP "Cluster:Group"
4848
#define MSCLUSTER_GROUPINDEX -101
49+
#define MSCLUSTER_BASEFID "Cluster:BaseFID"
50+
#define MSCLUSTER_BASEFIDINDEX -102
4951

5052
typedef struct cluster_tree_node clusterTreeNode;
5153
typedef struct cluster_info clusterInfo;
@@ -115,6 +117,10 @@ struct cluster_layer_info {
115117
clusterInfo* current;
116118
/* check whether all shapes should be returned behind a cluster */
117119
int get_all_shapes;
120+
/* check whether the location of the shapes should be preserved (no averaging) */
121+
int keep_locations;
122+
/* the maxdistance and the buffer parameters are specified in map units (scale independent clustering) */
123+
int use_map_units;
118124
double rank;
119125
/* root node of the quad tree */
120126
clusterTreeNode* root;
@@ -496,6 +502,11 @@ static void InitShapeAttributes(layerObj* layer, clusterInfo* base)
496502
base->shape.values[i] = msStrdup(base->group);
497503
else
498504
base->shape.values[i] = msStrdup("");
505+
} else if (itemindexes[i] == MSCLUSTER_BASEFIDINDEX) {
506+
if (base->shape.values[i])
507+
msFree(base->shape.values[i]);
508+
509+
base->shape.values[i] = msIntToString(base->shape.index);
499510
} else if (EQUALN(layer->items[i], "Count:", 6)) {
500511
if (base->shape.values[i])
501512
msFree(base->shape.values[i]);
@@ -522,6 +533,12 @@ static void UpdateShapeAttributes(layerObj* layer, clusterInfo* base, clusterInf
522533
if (current->shape.numvalues <= i)
523534
break;
524535

536+
/* setting the base feature index for each cluster member */
537+
if (itemindexes[i] == MSCLUSTER_BASEFIDINDEX) {
538+
msFree(current->shape.values[i]);
539+
current->shape.values[i] = msIntToString(base->shape.index);
540+
}
541+
525542
if (current->shape.values[i]) {
526543
if (EQUALN(layer->items[i], "Min:", 4)) {
527544
if (strcasecmp(base->shape.values[i], current->shape.values[i]) > 0) {
@@ -567,6 +584,8 @@ static int BuildFeatureAttributes(layerObj* layer, msClusterLayerInfo* layerinfo
567584
values[i] = NULL; /* not yet assigned */
568585
} else if (itemindexes[i] == MSCLUSTER_GROUPINDEX) {
569586
values[i] = NULL; /* not yet assigned */
587+
} else if (itemindexes[i] == MSCLUSTER_BASEFIDINDEX) {
588+
values[i] = NULL; /* not yet assigned */
570589
} else if (shape->values[itemindexes[i]])
571590
values[i] = msStrdup(shape->values[itemindexes[i]]);
572591
else
@@ -779,8 +798,11 @@ int selectClusterShape(layerObj* layer, long shapeindex)
779798

780799
current->next = current->siblings;
781800
layerinfo->current = current;
782-
current->shape.line[0].point[0].x = current->shape.bounds.minx = current->shape.bounds.maxx = current->avgx;
783-
current->shape.line[0].point[0].y = current->shape.bounds.miny = current->shape.bounds.maxy = current->avgy;
801+
802+
if (layerinfo->keep_locations == MS_FALSE) {
803+
current->shape.line[0].point[0].x = current->shape.bounds.minx = current->shape.bounds.maxx = current->avgx;
804+
current->shape.line[0].point[0].y = current->shape.bounds.miny = current->shape.bounds.maxy = current->avgy;
805+
}
784806

785807
return MS_SUCCESS;
786808
}
@@ -893,6 +915,19 @@ int RebuildClusters(layerObj *layer, int isQuery)
893915
else
894916
layerinfo->get_all_shapes = MS_FALSE;
895917

918+
/* check whether the location of the shapes should be preserved (no averaging) */
919+
if(msLayerGetProcessingKey(layer, "CLUSTER_KEEP_LOCATIONS") != NULL)
920+
layerinfo->keep_locations = MS_TRUE;
921+
else
922+
layerinfo->keep_locations = MS_FALSE;
923+
924+
/* check whether the maxdistance and the buffer parameters
925+
are specified in map units (scale independent clustering) */
926+
if(msLayerGetProcessingKey(layer, "CLUSTER_USE_MAP_UNITS") != NULL)
927+
layerinfo->use_map_units = MS_TRUE;
928+
else
929+
layerinfo->use_map_units = MS_FALSE;
930+
896931
/* identify the current extent */
897932
if(layer->transform == MS_TRUE)
898933
searchrect = map->extent;
@@ -931,16 +966,25 @@ int RebuildClusters(layerObj *layer, int isQuery)
931966
/* trying to find a reasonable quadtree depth */
932967
depth = 0;
933968
distance = layer->cluster.maxdistance;
934-
while ((distance < map->width || distance < map->height) && depth <= TREE_MAX_DEPTH) {
935-
distance *= 2;
936-
++depth;
969+
if (layerinfo->use_map_units == MS_TRUE) {
970+
while ((distance < (searchrect.maxx - searchrect.minx) || distance < (searchrect.maxy - searchrect.miny)) && depth <= TREE_MAX_DEPTH) {
971+
distance *= 2;
972+
++depth;
973+
}
974+
cellSizeX = 1;
975+
cellSizeY = 1;
976+
}
977+
else {
978+
while ((distance < map->width || distance < map->height) && depth <= TREE_MAX_DEPTH) {
979+
distance *= 2;
980+
++depth;
981+
}
982+
cellSizeX = MS_CELLSIZE(searchrect.minx, searchrect.maxx, map->width);
983+
cellSizeY = MS_CELLSIZE(searchrect.miny, searchrect.maxy, map->height);
937984
}
938985

939986
layerinfo->depth = depth;
940987

941-
cellSizeX = MS_CELLSIZE(searchrect.minx, searchrect.maxx, map->width);
942-
cellSizeY = MS_CELLSIZE(searchrect.miny, searchrect.maxy, map->height);
943-
944988
maxDistanceX = layer->cluster.maxdistance * cellSizeX;
945989
maxDistanceY = layer->cluster.maxdistance * cellSizeY;
946990

@@ -1213,6 +1257,8 @@ int msClusterLayerInitItemInfo(layerObj *layer)
12131257
itemindexes[i] = MSCLUSTER_FEATURECOUNTINDEX;
12141258
else if (EQUAL(layer->items[i], MSCLUSTER_GROUP))
12151259
itemindexes[i] = MSCLUSTER_GROUPINDEX;
1260+
else if (EQUAL(layer->items[i], MSCLUSTER_BASEFID))
1261+
itemindexes[i] = MSCLUSTER_BASEFIDINDEX;
12161262
else
12171263
itemindexes[i] = numitems++;
12181264
}
@@ -1266,8 +1312,10 @@ static int prepareShape(layerObj* layer, msClusterLayerInfo* layerinfo, clusterI
12661312
}
12671313

12681314
/* update the positions of the cluster shape */
1269-
shape->line[0].point[0].x = shape->bounds.minx = shape->bounds.maxx = current->avgx;
1270-
shape->line[0].point[0].y = shape->bounds.miny = shape->bounds.maxy = current->avgy;
1315+
if (layerinfo->keep_locations == MS_FALSE) {
1316+
shape->line[0].point[0].x = shape->bounds.minx = shape->bounds.maxx = current->avgx;
1317+
shape->line[0].point[0].y = shape->bounds.miny = shape->bounds.maxy = current->avgy;
1318+
}
12711319

12721320
return MS_SUCCESS;
12731321
}
@@ -1330,6 +1378,7 @@ int msClusterLayerGetItems(layerObj *layer)
13301378
layer->items = msSmallMalloc(sizeof(char*) * (layer->numitems));
13311379
layer->items[0] = msStrdup(MSCLUSTER_FEATURECOUNT);
13321380
layer->items[1] = msStrdup(MSCLUSTER_GROUP);
1381+
layer->items[2] = msStrdup(MSCLUSTER_BASEFID);
13331382

13341383
return msClusterLayerInitItemInfo(layer);
13351384
}

0 commit comments

Comments
 (0)