Skip to content

Commit

Permalink
[Backport branch-8-0] Refresh cached reprojector when changing map pr…
Browse files Browse the repository at this point in the history
…ojection between drawMap() calls (fixes #6896) (#6899)
  • Loading branch information
github-actions[bot] committed Jun 2, 2023
1 parent 8de60af commit d84d3f1
Show file tree
Hide file tree
Showing 13 changed files with 169 additions and 74 deletions.
24 changes: 8 additions & 16 deletions mapdraw.c
Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand Down
19 changes: 19 additions & 0 deletions maplayer.c
Expand Up @@ -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;
Expand Down
20 changes: 6 additions & 14 deletions mapogcsos.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}

Expand Down
10 changes: 3 additions & 7 deletions mapogroutput.cpp
Expand Up @@ -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;
}
Expand Down
27 changes: 27 additions & 0 deletions mapproject.c
Expand Up @@ -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;

/* -------------------------------------------------------------------- */
Expand Down Expand Up @@ -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;

/* -------------------------------------------------------------------- */
Expand Down Expand Up @@ -626,6 +636,7 @@ int msInitProjection(projectionObj *p)
#elif PJ_VERSION >= 480
p->proj_ctx = NULL;
#endif
p->generation_number = 0;
return(0);
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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() */
/* */
Expand Down
6 changes: 5 additions & 1 deletion mapproject.h
Expand Up @@ -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
Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions mapserver.h
Expand Up @@ -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);

Expand Down
50 changes: 15 additions & 35 deletions maptemplate.c
Expand Up @@ -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);
}
}

Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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);
}
}

Expand Down
49 changes: 49 additions & 0 deletions msautotest/mspython/test_bug_check.py
Expand Up @@ -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)
Binary file added msautotest/php/expected/setprojection-3857.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added msautotest/php/expected/setprojection-3978.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit d84d3f1

Please sign in to comment.