From 6facda6599f3d49b219e2b14013a104726387cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C4=81ris=20Narti=C5=A1s?= Date: Wed, 17 Jul 2024 23:17:22 +0300 Subject: [PATCH] Fix style scale factor inheritance Commit ede4953 introduced SIZEUNITS inheritance layer->class->style/label. When LAYER STYLEITEM is in use, for each feature msUpdateStyleFromString is called but no attempts are made to ensure correct scale factor values for newly created style item thus all features get scale factor 1.0, that might be different from value it should have. This wasn't a problem before ede4953 as layer scale factor was always used to render features with STYLEITEM. This commit introduces a workaround by lifting out code from the only place where scale factor is adjusted in a way that it can be reused also in the STYLEITEM case. --- src/mapdraw.c | 154 +++++++++++++++++++++++++++--------------------- src/maplayer.c | 5 ++ src/mapserver.h | 3 + 3 files changed, 96 insertions(+), 66 deletions(-) diff --git a/src/mapdraw.c b/src/mapdraw.c index eb41875d77..19600e4b8e 100644 --- a/src/mapdraw.c +++ b/src/mapdraw.c @@ -36,6 +36,92 @@ #include "mapows.h" #include "cpl_port.h" +/* msGetGeoCellSize + * + * A helper function to get the first parameter for msUpdateClassScaleFactor() + */ +double msGetGeoCellSize(const mapObj *map) +{ + double geo_cellsize; + + /* We will need a cellsize that represents a real georeferenced */ + /* coordinate cellsize here, so compute it from saved extents. */ + + geo_cellsize = map->cellsize; + if (map->gt.need_geotransform == MS_TRUE) { + double cellsize_x = + (map->saved_extent.maxx - map->saved_extent.minx) / map->width; + double cellsize_y = + (map->saved_extent.maxy - map->saved_extent.miny) / map->height; + + geo_cellsize = + sqrt(cellsize_x * cellsize_x + cellsize_y * cellsize_y) / sqrt(2.0); + } + return geo_cellsize; +} + +/* msUpdateClassScaleFactor + * + * Provides correct scale factor inheritance for Class and all of its + * styles and labels. + */ +void msUpdateClassScaleFactor(double geo_cellsize, const mapObj *map, const layerObj *layer, classObj *c) +{ + if (c->sizeunits == MS_INHERIT) + c->scalefactor = layer->scalefactor; + else if (c->sizeunits != MS_PIXELS) + c->scalefactor = (msInchesPerUnit(c->sizeunits, 0) / + msInchesPerUnit(map->units, 0)) / + geo_cellsize; + else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) + c->scalefactor = layer->symbolscaledenom / map->scaledenom * + map->resolution / map->defresolution; + else + c->scalefactor = map->resolution / map->defresolution; + for (int sid = 0; sid < c->numstyles; sid++) { + styleObj *style = c->styles[sid]; + if (style->sizeunits == MS_INHERIT) + style->scalefactor = c->scalefactor; + else if (style->sizeunits != MS_PIXELS) + style->scalefactor = (msInchesPerUnit(style->sizeunits, 0) / + msInchesPerUnit(map->units, 0)) / + geo_cellsize; + else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) + style->scalefactor = layer->symbolscaledenom / map->scaledenom * + map->resolution / map->defresolution; + else + style->scalefactor = map->resolution / map->defresolution; + } + for (int sid = 0; sid < c->numlabels; sid++) { + labelObj *label = c->labels[sid]; + if (label->sizeunits == MS_INHERIT) + label->scalefactor = c->scalefactor; + else if (label->sizeunits != MS_PIXELS) + label->scalefactor = (msInchesPerUnit(label->sizeunits, 0) / + msInchesPerUnit(map->units, 0)) / + geo_cellsize; + else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) + label->scalefactor = layer->symbolscaledenom / map->scaledenom * + map->resolution / map->defresolution; + else + label->scalefactor = map->resolution / map->defresolution; + for (int lsid = 0; lsid < label->numstyles; lsid++) { + styleObj *lstyle = label->styles[lsid]; + if (lstyle->sizeunits == MS_INHERIT) + lstyle->scalefactor = label->scalefactor; + else if (lstyle->sizeunits != MS_PIXELS) + lstyle->scalefactor = (msInchesPerUnit(lstyle->sizeunits, 0) / + msInchesPerUnit(map->units, 0)) / + geo_cellsize; + else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) + lstyle->scalefactor = layer->symbolscaledenom / map->scaledenom * + map->resolution / map->defresolution; + else + lstyle->scalefactor = map->resolution / map->defresolution; + } + } +} + /* msPrepareImage() * * Returns a new imageObj ready for rendering the current map. @@ -154,19 +240,7 @@ imageObj *msPrepareImage(mapObj *map, int allow_nonsquare) { if (map->gt.need_geotransform) msMapSetFakedExtent(map); - /* We will need a cellsize that represents a real georeferenced */ - /* coordinate cellsize here, so compute it from saved extents. */ - - geo_cellsize = map->cellsize; - if (map->gt.need_geotransform == MS_TRUE) { - double cellsize_x = - (map->saved_extent.maxx - map->saved_extent.minx) / map->width; - double cellsize_y = - (map->saved_extent.maxy - map->saved_extent.miny) / map->height; - - geo_cellsize = - sqrt(cellsize_x * cellsize_x + cellsize_y * cellsize_y) / sqrt(2.0); - } + geo_cellsize = msGetGeoCellSize(map); /* compute layer/class/style/label scale factors now */ for (int lid = 0; lid < map->numlayers; lid++) { @@ -182,59 +256,7 @@ imageObj *msPrepareImage(mapObj *map, int allow_nonsquare) { layer->scalefactor = map->resolution / map->defresolution; for (int cid = 0; cid < layer->numclasses; cid++) { classObj *class = GET_CLASS(map, lid, cid); - if (class->sizeunits == MS_INHERIT) - class->scalefactor = layer->scalefactor; - else if (class->sizeunits != MS_PIXELS) - class->scalefactor = (msInchesPerUnit(class->sizeunits, 0) / - msInchesPerUnit(map->units, 0)) / - geo_cellsize; - else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) - class->scalefactor = layer->symbolscaledenom / map->scaledenom * - map->resolution / map->defresolution; - else - class->scalefactor = map->resolution / map->defresolution; - for (int sid = 0; sid < class->numstyles; sid++) { - styleObj *style = class->styles[sid]; - if (style->sizeunits == MS_INHERIT) - style->scalefactor = class->scalefactor; - else if (style->sizeunits != MS_PIXELS) - style->scalefactor = (msInchesPerUnit(style->sizeunits, 0) / - msInchesPerUnit(map->units, 0)) / - geo_cellsize; - else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) - style->scalefactor = layer->symbolscaledenom / map->scaledenom * - map->resolution / map->defresolution; - else - style->scalefactor = map->resolution / map->defresolution; - } - for (int sid = 0; sid < class->numlabels; sid++) { - labelObj *label = class->labels[sid]; - if (label->sizeunits == MS_INHERIT) - label->scalefactor = class->scalefactor; - else if (label->sizeunits != MS_PIXELS) - label->scalefactor = (msInchesPerUnit(label->sizeunits, 0) / - msInchesPerUnit(map->units, 0)) / - geo_cellsize; - else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) - label->scalefactor = layer->symbolscaledenom / map->scaledenom * - map->resolution / map->defresolution; - else - label->scalefactor = map->resolution / map->defresolution; - for (int lsid = 0; lsid < label->numstyles; lsid++) { - styleObj *lstyle = label->styles[lsid]; - if (lstyle->sizeunits == MS_INHERIT) - lstyle->scalefactor = label->scalefactor; - else if (lstyle->sizeunits != MS_PIXELS) - lstyle->scalefactor = (msInchesPerUnit(lstyle->sizeunits, 0) / - msInchesPerUnit(map->units, 0)) / - geo_cellsize; - else if (layer->symbolscaledenom > 0 && map->scaledenom > 0) - lstyle->scalefactor = layer->symbolscaledenom / map->scaledenom * - map->resolution / map->defresolution; - else - lstyle->scalefactor = map->resolution / map->defresolution; - } - } + msUpdateClassScaleFactor(geo_cellsize, map, layer, class); } } diff --git a/src/maplayer.c b/src/maplayer.c index af76c0645e..15be16e22e 100644 --- a/src/maplayer.c +++ b/src/maplayer.c @@ -1395,6 +1395,9 @@ int msLayerGetFeatureStyle(mapObj *map, layerObj *layer, classObj *c, } msUpdateStyleFromString(c->styles[0], stylestring); + double geo_cellsize = msGetGeoCellSize(map); + msUpdateClassScaleFactor(geo_cellsize, map, layer, c); + if (c->styles[0]->symbolname) { if ((c->styles[0]->symbol = msGetSymbolIndex( &(map->symbolset), c->styles[0]->symbolname, MS_TRUE)) == -1) { @@ -1412,6 +1415,8 @@ int msLayerGetFeatureStyle(mapObj *map, layerObj *layer, classObj *c, c->layer = layer; } msUpdateClassFromString(c, stylestring); + double geo_cellsize = msGetGeoCellSize(map); + msUpdateClassScaleFactor(geo_cellsize, map, layer, c); } else if (strncasecmp(stylestring, "pen", 3) == 0 || strncasecmp(stylestring, "brush", 5) == 0 || strncasecmp(stylestring, "symbol", 6) == 0 || diff --git a/src/mapserver.h b/src/mapserver.h index d99f50faf2..0ec1ef79b0 100644 --- a/src/mapserver.h +++ b/src/mapserver.h @@ -3282,6 +3282,9 @@ rectObj msUVRASTERGetSearchRect(layerObj *layer, mapObj *map); /* Prototypes for functions in mapdraw.c */ /* ==================================================================== */ +MS_DLL_EXPORT double msGetGeoCellSize(const mapObj *map); +MS_DLL_EXPORT void msUpdateClassScaleFactor(double geo_cellsize, const mapObj *map, + const layerObj *layer, classObj *c); MS_DLL_EXPORT imageObj *msPrepareImage(mapObj *map, int allow_nonsquare); MS_DLL_EXPORT imageObj *msDrawMap(mapObj *map, int querymap); MS_DLL_EXPORT int msLayerIsVisible(mapObj *map, layerObj *layer);