From d84d3f1fb4ae43e3c8df31b5867253d0f3549ef1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 17:03:29 -0300 Subject: [PATCH] [Backport branch-8-0] Refresh cached reprojector when changing map projection between drawMap() calls (fixes #6896) (#6899) --- mapdraw.c | 24 +++------ maplayer.c | 19 +++++++ mapogcsos.c | 20 +++---- mapogroutput.cpp | 10 ++-- mapproject.c | 27 ++++++++++ mapproject.h | 6 ++- mapserver.h | 2 + maptemplate.c | 50 ++++++------------ msautotest/mspython/test_bug_check.py | 49 +++++++++++++++++ .../php/expected/setprojection-3857.png | Bin 0 -> 3236 bytes .../php/expected/setprojection-3978.png | Bin 0 -> 2283 bytes msautotest/php/mapObjTest.php | 34 +++++++++++- msautotest/php/result/.gitignore | 2 + 13 files changed, 169 insertions(+), 74 deletions(-) create mode 100644 msautotest/php/expected/setprojection-3857.png create mode 100644 msautotest/php/expected/setprojection-3978.png create mode 100644 msautotest/php/result/.gitignore diff --git a/mapdraw.c b/mapdraw.c index 60d6c1f2f4..431816562d 100644 --- a/mapdraw.c +++ b/mapdraw.c @@ -1770,16 +1770,12 @@ int pointLayerDrawShape(mapObj *map, imageObj *image, layerObj *layer, shapeObj if (layer->project && layer->transform == MS_TRUE) { - if( layer->reprojectorLayerToMap == NULL ) + reprojectionObj* reprojector = msLayerGetReprojectorToMap(layer, map); + if( reprojector == NULL ) { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &map->projection); - if( layer->reprojectorLayerToMap == NULL ) - { - return MS_FAILURE; - } + return MS_FAILURE; } - msProjectShapeEx(layer->reprojectorLayerToMap, shape); + msProjectShapeEx(reprojector, shape); } // Only take into account map rotation if the label and style angles are @@ -2098,16 +2094,12 @@ int msDrawShape(mapObj *map, layerObj *layer, shapeObj *shape, imageObj *image, if (layer->project && layer->transform == MS_TRUE) { - if( layer->reprojectorLayerToMap == NULL ) + reprojectionObj* reprojector = msLayerGetReprojectorToMap(layer, map); + if( reprojector == NULL ) { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &map->projection); - if( layer->reprojectorLayerToMap == NULL ) - { - return MS_FAILURE; - } + return MS_FAILURE; } - msProjectShapeEx(layer->reprojectorLayerToMap, shape); + msProjectShapeEx(reprojector, shape); } /* check if we'll need the unclipped shape */ diff --git a/maplayer.c b/maplayer.c index 7ef90320d2..2c29dd6ead 100644 --- a/maplayer.c +++ b/maplayer.c @@ -1915,6 +1915,25 @@ void msLayerEnablePaging(layerObj *layer, int value) layer->vtable->LayerEnablePaging(layer, value); } +/** Returns a cached reprojector from the layer projection to the map projection */ +reprojectionObj* msLayerGetReprojectorToMap(layerObj* layer, mapObj* map) +{ + if( layer->reprojectorLayerToMap != NULL && + !msProjectIsReprojectorStillValid(layer->reprojectorLayerToMap) ) + { + msProjectDestroyReprojector(layer->reprojectorLayerToMap); + layer->reprojectorLayerToMap = NULL; + } + + if( layer->reprojectorLayerToMap == NULL ) + { + layer->reprojectorLayerToMap = msProjectCreateReprojector( + &layer->projection, &map->projection); + } + return layer->reprojectorLayerToMap; +} + + int LayerDefaultGetExtent(layerObj *layer, rectObj *extent) { (void)layer; diff --git a/mapogcsos.c b/mapogcsos.c index eda0393dd5..5c45631f86 100644 --- a/mapogcsos.c +++ b/mapogcsos.c @@ -362,14 +362,10 @@ void msSOSAddGeometryNode(xmlNsPtr psNsGml, xmlNsPtr psNsMs, xmlNodePtr psParen if (psParent && psShape) { if (msProjectionsDiffer(&map->projection, &lp->projection) == MS_TRUE) { - if( lp->reprojectorLayerToMap == NULL ) + reprojectionObj* reprojector = msLayerGetReprojectorToMap(lp, map); + if( reprojector ) { - lp->reprojectorLayerToMap = msProjectCreateReprojector( - &lp->projection, &map->projection); - } - if( lp->reprojectorLayerToMap ) - { - msProjectShapeEx(lp->reprojectorLayerToMap, psShape); + msProjectShapeEx(reprojector, psShape); } msOWSGetEPSGProj(&(map->projection), &(lp->metadata), "SO", MS_TRUE, &pszEpsg_buf); pszEpsg = pszEpsg_buf; @@ -780,14 +776,10 @@ void msSOSAddMemberNode(xmlNsPtr psNsGml, xmlNsPtr psNsOm, xmlNsPtr psNsSwe, xml if(msProjectionsDiffer(&(lp->projection), &(map->projection))) { - if( lp->reprojectorLayerToMap == NULL ) - { - lp->reprojectorLayerToMap = msProjectCreateReprojector( - &lp->projection, &map->projection); - } - if( lp->reprojectorLayerToMap ) + reprojectionObj* reprojector = msLayerGetReprojectorToMap(lp, map); + if( reprojector ) { - msProjectShapeEx(lp->reprojectorLayerToMap, &sShape); + msProjectShapeEx(reprojector, &sShape); } } diff --git a/mapogroutput.cpp b/mapogroutput.cpp index 93f88f633b..53a2222a4f 100644 --- a/mapogroutput.cpp +++ b/mapogroutput.cpp @@ -1136,13 +1136,9 @@ int msOGRWriteFromQuery( mapObj *map, outputFormatObj *format, int sendheaders ) } if( layer->project && resultshape.type != MS_SHAPE_NULL) { - if( layer->reprojectorLayerToMap == NULL ) - { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &layer->map->projection); - } - if( layer->reprojectorLayerToMap ) - status = msProjectShapeEx(layer->reprojectorLayerToMap, &resultshape); + reprojectionObj* reprojector = msLayerGetReprojectorToMap(layer, layer->map); + if( reprojector ) + status = msProjectShapeEx(reprojector, &resultshape); else status = MS_FAILURE; } diff --git a/mapproject.c b/mapproject.c index f6dde810c3..215781575a 100644 --- a/mapproject.c +++ b/mapproject.c @@ -414,11 +414,19 @@ void msProjectionContextUnref(projectionContext* ctx) /* msProjectCreateReprojector() */ /************************************************************************/ +/* The pointed objects need to remain valid during the lifetime of the + * reprojector, as only their pointer is stored. + * + * If the *content* of in and/or out is changed, then the reprojector is + * no longer valid. This can be detected with msProjectIsReprojectorStillValid() + */ reprojectionObj* msProjectCreateReprojector(projectionObj* in, projectionObj* out) { reprojectionObj* obj = (reprojectionObj*)msSmallCalloc(1, sizeof(reprojectionObj)); obj->in = in; obj->out = out; + obj->generation_number_in = in ? in->generation_number : 0; + obj->generation_number_out = out ? out->generation_number : 0; obj->lineCuttingCase = LINE_CUTTING_UNKNOWN; /* -------------------------------------------------------------------- */ @@ -551,6 +559,8 @@ reprojectionObj* msProjectCreateReprojector(projectionObj* in, projectionObj* ou obj = (reprojectionObj*)msSmallCalloc(1, sizeof(reprojectionObj)); obj->in = in; obj->out = out; + obj->generation_number_in = in ? in->generation_number : 0; + obj->generation_number_out = out ? out->generation_number : 0; obj->lineCuttingCase = LINE_CUTTING_UNKNOWN; /* -------------------------------------------------------------------- */ @@ -626,6 +636,7 @@ int msInitProjection(projectionObj *p) #elif PJ_VERSION >= 480 p->proj_ctx = NULL; #endif + p->generation_number = 0; return(0); } @@ -654,6 +665,7 @@ void msFreeProjection(projectionObj *p) msFreeCharArray(p->args, p->numargs); p->args = NULL; p->numargs = 0; + p->generation_number ++; } void msFreeProjectionExceptContext(projectionObj *p) @@ -845,6 +857,8 @@ int msProcessProjection(projectionObj *p) { assert( p->proj == NULL ); + p->generation_number ++; + if( strcasecmp(p->args[0],"GEOGRAPHIC") == 0 ) { msSetError(MS_PROJERR, "PROJECTION 'GEOGRAPHIC' no longer supported.\n" @@ -1367,6 +1381,19 @@ static msLineCuttingCase msProjectGetLineCuttingCase(reprojectionObj* reprojecto } #endif +/************************************************************************/ +/* msProjectIsReprojectorStillValid() */ +/************************************************************************/ + +int msProjectIsReprojectorStillValid(reprojectionObj* reprojector) +{ + if( reprojector->in && reprojector->in->generation_number != reprojector->generation_number_in ) + return MS_FALSE; + if( reprojector->out && reprojector->out->generation_number != reprojector->generation_number_out ) + return MS_FALSE; + return MS_TRUE; +} + /************************************************************************/ /* msProjectShapeLine() */ /* */ diff --git a/mapproject.h b/mapproject.h index 2d54c60278..b84574c9a6 100644 --- a/mapproject.h +++ b/mapproject.h @@ -89,7 +89,8 @@ but are not directly exposed by the mapscript module %immutable; #endif int numargs; ///< Actual number of projection args - int automatic; ///< Projection object was to fetched from the layer + short automatic; ///< Projection object was to fetched from the layer + unsigned short generation_number; ///< To be incremented when the content of the object change, so that reprojector can be invalidated #ifdef SWIG %mutable; #endif @@ -116,12 +117,15 @@ but are not directly exposed by the mapscript module int no_op; #endif #endif + unsigned short generation_number_in; + unsigned short generation_number_out; } reprojectionObj; #ifndef SWIG MS_DLL_EXPORT reprojectionObj* msProjectCreateReprojector(projectionObj* in, projectionObj* out); MS_DLL_EXPORT void msProjectDestroyReprojector(reprojectionObj* reprojector); + MS_DLL_EXPORT int msProjectIsReprojectorStillValid(reprojectionObj* reprojector); MS_DLL_EXPORT projectionContext* msProjectionContextGetFromPool(void); MS_DLL_EXPORT void msProjectionContextReleaseToPool(projectionContext* ctx); diff --git a/mapserver.h b/mapserver.h index 9359a2fcac..586ed07fad 100755 --- a/mapserver.h +++ b/mapserver.h @@ -2618,6 +2618,8 @@ extern "C" { int msOGRLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record); int msOGRLayerGetExtent(layerObj *layer, rectObj *extent); + reprojectionObj MS_DLL_EXPORT* msLayerGetReprojectorToMap(layerObj* layer, mapObj* map); + MS_DLL_EXPORT int msOGRGeometryToShape(OGRGeometryH hGeometry, shapeObj *shape, OGRwkbGeometryType type); diff --git a/maptemplate.c b/maptemplate.c index 643e5c940e..ae144e75ad 100644 --- a/maptemplate.c +++ b/maptemplate.c @@ -1619,14 +1619,10 @@ static int processShplabelTag(layerObj *layer, char **line, shapeObj *origshape) if(layer->transform == MS_TRUE) { if(layer->project && msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) { - if( layer->reprojectorLayerToMap == NULL ) + reprojectionObj* reprojector = msLayerGetReprojectorToMap(layer, layer->map); + if( reprojector ) { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &layer->map->projection); - } - if( layer->reprojectorLayerToMap ) - { - msProjectShapeEx(layer->reprojectorLayerToMap, shape); + msProjectShapeEx(reprojector, shape); } } @@ -1640,14 +1636,10 @@ static int processShplabelTag(layerObj *layer, char **line, shapeObj *origshape) if(layer->transform == MS_TRUE) { if(layer->project && msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) { - if( layer->reprojectorLayerToMap == NULL ) + reprojectionObj* reprojector = msLayerGetReprojectorToMap(layer, layer->map); + if( reprojector ) { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &layer->map->projection); - } - if( layer->reprojectorLayerToMap ) - { - msProjectShapeEx(layer->reprojectorLayerToMap, shape); + msProjectShapeEx(reprojector, shape); } } @@ -1680,14 +1672,10 @@ static int processShplabelTag(layerObj *layer, char **line, shapeObj *origshape) if(layer->transform == MS_TRUE) { if(layer->project && msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) { - if( layer->reprojectorLayerToMap == NULL ) - { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &layer->map->projection); - } - if( layer->reprojectorLayerToMap ) + reprojectionObj* reprojector = msLayerGetReprojectorToMap(layer, layer->map); + if( reprojector ) { - msProjectShapeEx(layer->reprojectorLayerToMap, shape); + msProjectShapeEx(reprojector, shape); } } @@ -1778,14 +1766,10 @@ static int processShplabelTag(layerObj *layer, char **line, shapeObj *origshape) /* if necessary, project the shape to match the map */ if(msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) { - if( layer->reprojectorLayerToMap == NULL ) - { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &layer->map->projection); - } - if( layer->reprojectorLayerToMap ) + reprojectionObj* reprojector = msLayerGetReprojectorToMap(layer, layer->map); + if( reprojector ) { - msProjectShapeEx(layer->reprojectorLayerToMap, &tShape); + msProjectShapeEx(reprojector, &tShape); } } @@ -2155,14 +2139,10 @@ static int processShpxyTag(layerObj *layer, char **line, shapeObj *shape) /* if necessary, project the shape to match the map */ if(msProjectionsDiffer(&(layer->projection), &(layer->map->projection))) { - if( layer->reprojectorLayerToMap == NULL ) - { - layer->reprojectorLayerToMap = msProjectCreateReprojector( - &layer->projection, &layer->map->projection); - } - if( layer->reprojectorLayerToMap ) + reprojectionObj* reprojector = msLayerGetReprojectorToMap(layer, layer->map); + if( reprojector ) { - msProjectShapeEx(layer->reprojectorLayerToMap, &tShape); + msProjectShapeEx(reprojector, &tShape); } } diff --git a/msautotest/mspython/test_bug_check.py b/msautotest/mspython/test_bug_check.py index 168820425d..965987b569 100755 --- a/msautotest/mspython/test_bug_check.py +++ b/msautotest/mspython/test_bug_check.py @@ -232,3 +232,52 @@ def test_reprojection_from_lonlat_wrap_0(): set_x = [point11.x, point12.x, point21.x, point22.x] set_x.sort() assert set_x == pytest.approx([-180, -179, 178, 180], abs=1e-2) + + +############################################################################### +# Check that we can draw a map several times by changing the map projection + +def test_bug_6896(): + + try: + os.mkdir(get_relpath_to_this('result')) + except: + pass + + def load_map(): + # Generate a reference image + map = mapscript.mapObj(get_relpath_to_this('../misc/ogr_direct.map')) + layer = map.getLayer(0) + layer.setProjection('+proj=utm +zone=11 +datum=WGS84') + return map + + def draw_another_projection(map): + # Draw map with one reprojection. + map.setProjection('+proj=utm +zone=12 +datum=WGS84') + map.setExtent(-10675, 4781937, -7127, 4784428 ) + map.draw() + + def draw_wgs84(map): + # Draw map with WGS 84 projection + map.setProjection('+proj=latlong +datum=WGS84') + map.setExtent(-117.25,43.02,-117.21,43.05) + img = map.draw() + return img + + map = load_map() + img = draw_wgs84(map) + ref_filename = get_relpath_to_this('result/bug6896_ref.png') + img.save(ref_filename) + + # Reload map + map = load_map() + draw_another_projection(map) + img = draw_wgs84(map) + test_filename = get_relpath_to_this('result/bug6896.png') + img.save(test_filename) + + assert open(ref_filename, 'rb').read() == \ + open(test_filename, 'rb').read() + + os.unlink(ref_filename) + os.unlink(test_filename) diff --git a/msautotest/php/expected/setprojection-3857.png b/msautotest/php/expected/setprojection-3857.png new file mode 100644 index 0000000000000000000000000000000000000000..629da2cddca390d45ce39236492baf2b53f82e18 GIT binary patch literal 3236 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 aL|Aa7K3(u@n(7mS@No6UJ$L!`r~d+EN($8g literal 0 HcmV?d00001 diff --git a/msautotest/php/mapObjTest.php b/msautotest/php/mapObjTest.php index eb131d0319..f73e2f3cd9 100644 --- a/msautotest/php/mapObjTest.php +++ b/msautotest/php/mapObjTest.php @@ -74,9 +74,41 @@ public function test__setNumlayers() #$this->map->numlayers = 2; } + //also testing multiple setProjection cache issue #6896 + public function test__setProjection() + { + $map_file = 'maps/reprojection.map'; + $map = new mapObj($map_file); + $this->assertEquals(0, $map->setProjection('init=epsg:3857'), 'Failed to set MAP projection to EPSG:3857'); + $map->setExtent(-7913606, 5346829, -6120700, 6522760); + $layer = $map->getLayerByName('ns-places'); + $this->assertEquals(0, $layer->setProjection('init=epsg:4326'), 'Failed to set LAYER projection to EPSG:4326'); + $image4326 = $map->draw(); + $image4326->save('./result/setprojection-3857.png'); + //test multiple reprojections + $this->assertEquals(0, $map->setProjection('init=epsg:3978'), 'Failed to set MAP projection to EPSG:3978'); + $map->setExtent(1394924, -279190, 3376084, 1020214); + $image3978 = $map->draw(); + $image3978->save('./result/setprojection-3978.png'); + //compare the EPSG:3857 map image + $expectedImage3857 = './expected/setprojection-3857.png'; + $resultImage3857 = './result/setprojection-3857.png'; + $this->assertFileEquals($expectedImage3857 , $resultImage3857, 'Result setProjection EPSG:3857 map image is not same as Expected'); + //compare the EPSG:3978 map image + $expectedImage3978 = './expected/setprojection-3978.png'; + $resultImage3978 = './result/setprojection-3978.png'; + $this->assertFileEquals($expectedImage3978 , $resultImage3978, 'Result setProjection EPSG:3978 map image is not same as Expected'); + } + # destroy variables, if not can lead to segmentation fault public function tearDown(): void { - unset($map, $map_file, $this->map_file, $this->map->numoutputformats, $this->map->numlayers, $this->map->imagetype, $this->map->queryByRect, $this->map->saveQueryAsGML); + unset($map, $map_file); + unset($image4326, $image3978); + unset($expectedImage3857, $resultImage3857); + unset($expectedImage3978, $resultImage3978); + unset($this->map_file, $this->map->numoutputformats); + unset($this->map->numlayers, $this->map->imagetype); + unset($this->map->queryByRect, $this->map->saveQueryAsGML); } } diff --git a/msautotest/php/result/.gitignore b/msautotest/php/result/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/msautotest/php/result/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore