Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 3a56e50f9d
Fetching contributors…

Cannot retrieve contributors at this time

793 lines (642 sloc) 26.415 kb
/******************************************************************************
* $Id$
*
* Project: MapServer
* Purpose: Functions for operating on a mapObj that don't belong in a
* more specific file such as mapfile.c, or mapdraw.c.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2004, Frank Warmerdam
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies of this Software or works derived from this Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "mapserver.h"
#ifdef USE_GDAL
# include "gdal.h"
# include "cpl_conv.h"
#endif
void freeWeb(webObj *web);
void freeScalebar(scalebarObj *scalebar);
void freeReferenceMap(referenceMapObj *ref);
void freeLegend(legendObj *legend);
/************************************************************************/
/* msNewMapObj() */
/* */
/* Create a new initialized map object. */
/************************************************************************/
mapObj *msNewMapObj()
{
mapObj *map;
/* create an empty map, no layers etc... */
map = (mapObj *)calloc(sizeof(mapObj),1);
if(!map) {
msSetError(MS_MEMERR, NULL, "msCreateMap()");
return NULL;
}
if( initMap( map ) == -1 )
return NULL;
if( msPostMapParseOutputFormatSetup( map ) == MS_FAILURE )
return NULL;
return map;
}
/************************************************************************/
/* msFreeMap() */
/************************************************************************/
void msFreeMap(mapObj *map)
{
int i;
if(!map) return;
/* printf("msFreeMap(): maybe freeing map at %p count=%d.\n",map, map->refcount); */
if(MS_REFCNT_DECR_IS_NOT_ZERO(map)) {
return;
}
if(map->debug >= MS_DEBUGLEVEL_VV)
msDebug("msFreeMap(): freeing map at %p.\n",map);
msCloseConnections(map);
msFree(map->name);
msFree(map->shapepath);
msFree(map->mappath);
msFreeProjection(&(map->projection));
msFreeProjection(&(map->latlon));
msFreeLabelCache(&(map->labelcache));
msFree(map->imagetype);
msFreeFontSet(&(map->fontset));
msFreeSymbolSet(&map->symbolset); /* free symbols */
msFree(map->symbolset.filename);
freeWeb(&(map->web));
freeScalebar(&(map->scalebar));
freeReferenceMap(&(map->reference));
freeLegend(&(map->legend));
for(i=0; i<map->maxlayers; i++) {
if(GET_LAYER(map, i) != NULL) {
GET_LAYER(map, i)->map = NULL;
if(freeLayer((GET_LAYER(map, i))) == MS_SUCCESS)
free(GET_LAYER(map, i));
}
}
msFree(map->layers);
if(map->layerorder)
free(map->layerorder);
msFree(map->templatepattern);
msFree(map->datapattern);
msFreeHashItems(&(map->configoptions));
if(map->outputformat && map->outputformat->refcount > 0 && --map->outputformat->refcount < 1)
msFreeOutputFormat(map->outputformat);
for(i=0; i<map->numoutputformats; i++ ) {
if(map->outputformatlist[i]->refcount > 0 && --map->outputformatlist[i]->refcount < 1)
msFreeOutputFormat(map->outputformatlist[i]);
}
if(map->outputformatlist != NULL)
msFree(map->outputformatlist);
msFreeQuery(&(map->query));
msFree(map);
}
/************************************************************************/
/* msGetConfigOption() */
/************************************************************************/
const char *msGetConfigOption( mapObj *map, const char *key)
{
return msLookupHashTable( &(map->configoptions), key );
}
/************************************************************************/
/* msSetConfigOption() */
/************************************************************************/
int msSetConfigOption( mapObj *map, const char *key, const char *value)
{
/* We have special "early" handling of this so that it will be */
/* in effect when the projection blocks are parsed and pj_init is called. */
if( strcasecmp(key,"PROJ_LIB") == 0 ) {
/* value may be relative to map path */
msSetPROJ_LIB( value, map->mappath );
}
/* Same for MS_ERRORFILE, we want it to kick in as early as possible
* to catch parsing errors.
* Value can be relative to mapfile, unless it's already absolute
*/
if( strcasecmp(key,"MS_ERRORFILE") == 0 ) {
if (msSetErrorFile( value, map->mappath ) != MS_SUCCESS)
return MS_FAILURE;
}
if( msLookupHashTable( &(map->configoptions), key ) != NULL )
msRemoveHashTable( &(map->configoptions), key );
msInsertHashTable( &(map->configoptions), key, value );
return MS_SUCCESS;
}
/************************************************************************/
/* msTestConfigOption() */
/************************************************************************/
int msTestConfigOption( mapObj *map, const char *key, int default_result )
{
const char *result = msGetConfigOption( map, key );
if( result == NULL )
return default_result;
if( strcasecmp(result,"YES") == 0
|| strcasecmp(result,"ON") == 0
|| strcasecmp(result,"TRUE") == 0 )
return MS_TRUE;
else
return MS_FALSE;
}
/************************************************************************/
/* msApplyMapConfigOptions() */
/************************************************************************/
void msApplyMapConfigOptions( mapObj *map )
{
const char *key;
for( key = msFirstKeyFromHashTable( &(map->configoptions) );
key != NULL;
key = msNextKeyFromHashTable( &(map->configoptions), key ) ) {
const char *value = msLookupHashTable( &(map->configoptions), key );
if( strcasecmp(key,"PROJ_LIB") == 0 ) {
msSetPROJ_LIB( value, map->mappath );
} else if( strcasecmp(key,"MS_ERRORFILE") == 0 ) {
msSetErrorFile( value, map->mappath );
} else {
#if defined(USE_GDAL) && GDAL_RELEASE_DATE > 20030601
CPLSetConfigOption( key, value );
#endif
}
}
}
/************************************************************************/
/* msMapIgnoreMissingData() */
/************************************************************************/
int msMapIgnoreMissingData( mapObj *map )
{
const char *result = msGetConfigOption( map, "ON_MISSING_DATA" );
const int default_result =
#ifndef IGNORE_MISSING_DATA
MS_MISSING_DATA_FAIL;
#else
MS_MISSING_DATA_LOG;
#endif
if( result == NULL )
return default_result;
if( strcasecmp(result,"FAIL") == 0 )
return MS_MISSING_DATA_FAIL;
else if( strcasecmp(result,"LOG") == 0 )
return MS_MISSING_DATA_LOG;
else if( strcasecmp(result,"IGNORE") == 0 )
return MS_MISSING_DATA_IGNORE;
return default_result;
}
/************************************************************************/
/* msMapSetExtent() */
/************************************************************************/
int msMapSetExtent( mapObj *map,
double minx, double miny, double maxx, double maxy)
{
map->extent.minx = minx;
map->extent.miny = miny;
map->extent.maxx = maxx;
map->extent.maxy = maxy;
if (!MS_VALID_EXTENT(map->extent)) {
msSetError(MS_MISCERR, "Given map extent is invalid. Check that it " \
"is in the form: minx, miny, maxx, maxy", "setExtent()");
return MS_FAILURE;
}
map->cellsize = msAdjustExtent(&(map->extent), map->width,
map->height);
/* if the map size is also set, recompute scale, ignore errors? */
if( map->width != -1 || map->height != -1 )
msCalculateScale(map->extent, map->units, map->width, map->height,
map->resolution, &(map->scaledenom));
return msMapComputeGeotransform( map );
}
/************************************************************************/
/* msMapOffsetExtent() */
/************************************************************************/
int msMapOffsetExtent( mapObj *map, double x, double y)
{
return msMapSetExtent( map,
map->extent.minx + x, map->extent.miny + y,
map->extent.maxx + x, map->extent.maxy + y);
}
/************************************************************************/
/* msMapScaleExtent() */
/************************************************************************/
int msMapScaleExtent( mapObj *map, double zoomfactor,
double minscaledenom, double maxscaledenom)
{
double geo_width, geo_height, center_x, center_y, md;
if (zoomfactor <= 0.0) {
msSetError(MS_MISCERR, "The given zoomfactor is invalid", "msMapScaleExtent()");
}
geo_width = map->extent.maxx - map->extent.minx;
geo_height = map->extent.maxy - map->extent.miny;
center_x = map->extent.minx + geo_width * 0.5;
center_y = map->extent.miny + geo_height * 0.5;
geo_width *= zoomfactor;
if (minscaledenom > 0 || maxscaledenom > 0) {
/* ensure we are within the valid scale domain */
md = (map->width-1)/(map->resolution * msInchesPerUnit(map->units, center_y));
if (minscaledenom > 0 && geo_width < minscaledenom * md)
geo_width = minscaledenom * md;
if (maxscaledenom > 0 && geo_width > maxscaledenom * md)
geo_width = maxscaledenom * md;
}
geo_width *= 0.5;
geo_height = geo_width * map->height / map->width;
return msMapSetExtent( map,
center_x - geo_width, center_y - geo_height,
center_x + geo_width, center_y + geo_height);
}
/************************************************************************/
/* msMapSetCenter() */
/************************************************************************/
int msMapSetCenter( mapObj *map, pointObj *center)
{
return msMapOffsetExtent(map, center->x - (map->extent.minx + map->extent.maxx) * 0.5,
center->y - (map->extent.miny + map->extent.maxy) * 0.5);
}
/************************************************************************/
/* msMapSetRotation() */
/************************************************************************/
int msMapSetRotation( mapObj *map, double rotation_angle )
{
map->gt.rotation_angle = rotation_angle;
if( map->gt.rotation_angle != 0.0 )
map->gt.need_geotransform = MS_TRUE;
else
map->gt.need_geotransform = MS_FALSE;
return msMapComputeGeotransform( map );
}
/************************************************************************/
/* msMapSetSize() */
/************************************************************************/
int msMapSetSize( mapObj *map, int width, int height )
{
map->width = width;
map->height = height;
return msMapComputeGeotransform( map ); /* like SetRotation -- sean */
}
/************************************************************************/
/* msMapComputeGeotransform() */
/************************************************************************/
extern int InvGeoTransform( double *gt_in, double *gt_out );
int msMapComputeGeotransform( mapObj * map )
{
double rot_angle;
double geo_width, geo_height, center_x, center_y;
map->saved_extent = map->extent;
/* Do we have all required parameters? */
if( map->extent.minx == map->extent.maxx
|| map->width == 0 || map->height == 0 )
return MS_FAILURE;
rot_angle = map->gt.rotation_angle * MS_PI / 180.0;
geo_width = map->extent.maxx - map->extent.minx;
geo_height = map->extent.maxy - map->extent.miny;
center_x = map->extent.minx + geo_width*0.5;
center_y = map->extent.miny + geo_height*0.5;
/*
** Per bug 1916 we have to adjust for the fact that map extents
** are based on the center of the edge pixels, not the outer
** edges as is expected in a geotransform.
*/
map->gt.geotransform[1] =
cos(rot_angle) * geo_width / (map->width-1);
map->gt.geotransform[2] =
sin(rot_angle) * geo_height / (map->height-1);
map->gt.geotransform[0] = center_x
- (map->width * 0.5) * map->gt.geotransform[1]
- (map->height * 0.5) * map->gt.geotransform[2];
map->gt.geotransform[4] =
sin(rot_angle) * geo_width / (map->width-1);
map->gt.geotransform[5] =
- cos(rot_angle) * geo_height / (map->height-1);
map->gt.geotransform[3] = center_y
- (map->width * 0.5) * map->gt.geotransform[4]
- (map->height * 0.5) * map->gt.geotransform[5];
if( InvGeoTransform( map->gt.geotransform,
map->gt.invgeotransform ) )
return MS_SUCCESS;
else
return MS_FAILURE;
}
/************************************************************************/
/* msMapPixelToGeoref() */
/************************************************************************/
void msMapPixelToGeoref( mapObj *map, double *x, double *y )
{
msSetError(MS_MISCERR, NULL, "msMapPixelToGeoref() not yet implemented");
}
/************************************************************************/
/* msMapGeorefToPixel() */
/************************************************************************/
void msMapGeorefToPixel( mapObj *map, double *x, double *y )
{
msSetError(MS_MISCERR, NULL, "msMapGeorefToPixel() not yet implemented");
}
/************************************************************************/
/* msMapSetFakedExtent() */
/************************************************************************/
int msMapSetFakedExtent( mapObj *map )
{
int i;
/* -------------------------------------------------------------------- */
/* Remember the original map extents so we can restore them */
/* later. */
/* -------------------------------------------------------------------- */
map->saved_extent = map->extent;
/* -------------------------------------------------------------------- */
/* Set extents such that the bottom left corner is 0,0 and the */
/* top right is width,height. Note this is upside down from */
/* the normal sense of pixel/line coordiantes, but we do this */
/* so that the normal "extent" concept of coordinates */
/* increasing to the right, and up is maintained (like in */
/* georeferenced coordinate systems). */
/* -------------------------------------------------------------------- */
map->extent.minx = 0;
map->extent.maxx = map->width;
map->extent.miny = 0;
map->extent.maxy = map->height;
map->cellsize = 1.0;
/* -------------------------------------------------------------------- */
/* When we copy the geotransform into the projection object we */
/* have to flip it to account for the preceeding upside-down */
/* coordinate system. */
/* -------------------------------------------------------------------- */
map->projection.gt = map->gt;
map->projection.gt.geotransform[0]
+= map->height * map->gt.geotransform[2];
map->projection.gt.geotransform[3]
+= map->height * map->gt.geotransform[5];
map->projection.gt.geotransform[2] *= -1;
map->projection.gt.geotransform[5] *= -1;
for(i=0; i<map->numlayers; i++)
GET_LAYER(map, i)->project = MS_TRUE;
return InvGeoTransform( map->projection.gt.geotransform,
map->projection.gt.invgeotransform );
}
/************************************************************************/
/* msMapRestoreRealExtent() */
/************************************************************************/
int msMapRestoreRealExtent( mapObj *map )
{
map->projection.gt.need_geotransform = MS_FALSE;
map->extent = map->saved_extent;
map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height);
return MS_SUCCESS;
}
/************************************************************************/
/* msInsertLayer() */
/************************************************************************/
/* Returns the index at which the layer was inserted
*/
int msInsertLayer(mapObj *map, layerObj *layer, int nIndex)
{
if (!layer) {
msSetError(MS_CHILDERR, "Can't insert a NULL Layer", "msInsertLayer()");
return -1;
}
/* Ensure there is room for a new layer */
if (map->numlayers == map->maxlayers) {
if (msGrowMapLayers(map) == NULL)
return -1;
}
/* msGrowMapLayers allocates the new layer which we don't need to do since we have 1 that we are inserting
not sure if it is possible for this to be non null otherwise, but better to check since this function
replaces the value */
if (map->layers[map->numlayers]!=NULL)
free(map->layers[map->numlayers]);
/* Catch attempt to insert past end of layers array */
if (nIndex >= map->numlayers) {
msSetError(MS_CHILDERR, "Cannot insert layer beyond index %d",
"msInsertLayer()", map->numlayers-1);
return -1;
} else if (nIndex < 0) { /* Insert at the end by default */
map->layerorder[map->numlayers] = map->numlayers;
GET_LAYER(map, map->numlayers) = layer;
GET_LAYER(map, map->numlayers)->index = map->numlayers;
GET_LAYER(map, map->numlayers)->map = map;
MS_REFCNT_INCR(layer);
map->numlayers++;
return map->numlayers-1;
} else if (nIndex >= 0 && nIndex < map->numlayers) {
/* Move existing layers at the specified nIndex or greater */
/* to an index one higher */
int i;
for (i=map->numlayers; i>nIndex; i--) {
GET_LAYER(map, i)=GET_LAYER(map, i-1);
GET_LAYER(map, i)->index = i;
}
/* assign new layer to specified index */
GET_LAYER(map, nIndex)=layer;
GET_LAYER(map, nIndex)->index = nIndex;
GET_LAYER(map, nIndex)->map = map;
/* adjust layers drawing order */
for (i=map->numlayers; i>nIndex; i--) {
map->layerorder[i] = map->layerorder[i-1];
if (map->layerorder[i] >= nIndex) map->layerorder[i]++;
}
for (i=0; i<nIndex; i++) {
if (map->layerorder[i] >= nIndex) map->layerorder[i]++;
}
map->layerorder[nIndex] = nIndex;
/* increment number of layers and return */
MS_REFCNT_INCR(layer);
map->numlayers++;
return nIndex;
} else {
msSetError(MS_CHILDERR, "Invalid index", "msInsertLayer()");
return -1;
}
}
/************************************************************************/
/* msRemoveLayer() */
/************************************************************************/
layerObj *msRemoveLayer(mapObj *map, int nIndex)
{
int i;
int order_index;
layerObj *layer;
if (nIndex < 0 || nIndex >= map->numlayers) {
msSetError(MS_CHILDERR, "Cannot remove Layer, invalid index %d",
"msRemoveLayer()", nIndex);
return NULL;
} else {
layer=GET_LAYER(map, nIndex);
/* msCopyLayer(layer, (GET_LAYER(map, nIndex))); */
/* Iteratively copy the higher index layers down one index */
for (i=nIndex; i<map->numlayers-1; i++) {
/* freeLayer((GET_LAYER(map, i))); */
/* initLayer((GET_LAYER(map, i)), map); */
/* msCopyLayer(GET_LAYER(map, i), GET_LAYER(map, i+1)); */
GET_LAYER(map, i)=GET_LAYER(map, i+1);
GET_LAYER(map, i)->index = i;
}
/* Free the extra layer at the end */
/* freeLayer((GET_LAYER(map, map->numlayers-1))); */
GET_LAYER(map, map->numlayers-1)=NULL;
/* Adjust drawing order */
order_index = 0;
for (i=0; i<map->numlayers; i++) {
if (map->layerorder[i] > nIndex) map->layerorder[i]--;
if (map->layerorder[i] == nIndex) {
order_index = i;
break;
}
}
for (i=order_index; i<map->numlayers-1; i++) {
map->layerorder[i] = map->layerorder[i+1];
if (map->layerorder[i] > nIndex) map->layerorder[i]--;
}
/* decrement number of layers and return copy of removed layer */
map->numlayers--;
layer->map=NULL;
MS_REFCNT_DECR(layer);
return layer;
}
}
/*
** Move the layer's order for drawing purpose. Moving it up here
** will have the effect of drawing the layer earlier.
*/
int msMoveLayerUp(mapObj *map, int nLayerIndex)
{
int iCurrentIndex = -1;
int i = 0;
if (map && nLayerIndex < map->numlayers && nLayerIndex >=0) {
for (i=0; i<map->numlayers; i++) {
if ( map->layerorder[i] == nLayerIndex) {
iCurrentIndex = i;
break;
}
}
if (iCurrentIndex >=0) {
/* we do not need to promote if it is the first one. */
if (iCurrentIndex == 0)
return MS_FAILURE;
map->layerorder[iCurrentIndex] =
map->layerorder[iCurrentIndex-1];
map->layerorder[iCurrentIndex-1] = nLayerIndex;
return MS_SUCCESS;
}
}
msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveLayerUp()",
nLayerIndex);
return MS_FAILURE;
}
/*
** Move the layer's order for drawing purpose. Moving it down here
** will have the effect of drawing the layer later.
*/
int msMoveLayerDown(mapObj *map, int nLayerIndex)
{
int iCurrentIndex = -1;
int i = 0;
if (map && nLayerIndex < map->numlayers && nLayerIndex >=0) {
for (i=0; i<map->numlayers; i++) {
if ( map->layerorder[i] == nLayerIndex) {
iCurrentIndex = i;
break;
}
}
if (iCurrentIndex >=0) {
/* we do not need to demote if it is the last one. */
if (iCurrentIndex == map->numlayers-1)
return MS_FAILURE;
map->layerorder[iCurrentIndex] =
map->layerorder[iCurrentIndex+1];
map->layerorder[iCurrentIndex+1] = nLayerIndex;
return MS_SUCCESS;
}
}
msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveLayerDown()",
nLayerIndex);
return MS_FAILURE;
}
/*
** Set the array used for the drawing order. The array passed must contain
** all the layer's index ordered by the drawing priority.
** Ex : for 3 layers in the map file, if
** panIndexes[0] = 2
** panIndexes[1] = 0
** panIndexes[2] = 1
** will set the darwing order to layer 2, layer 0,
** and then layer 1.
**
** Note : It is assumed that the index panIndexes has the same number of
** of elements as the number of layers in the map.
** Return TRUE on success else FALSE.
*/
int msSetLayersdrawingOrder(mapObj *self, int *panIndexes)
{
int nElements = 0;
int i, j = 0;
int bFound = 0;
if (self && panIndexes) {
nElements = self->numlayers;
for (i=0; i<nElements; i++) {
bFound = 0;
for (j=0; j<nElements; j++) {
if (panIndexes[j] == i) {
bFound = 1;
break;
}
}
if (!bFound)
return 0;
}
/* -------------------------------------------------------------------- */
/* At this point the array is valid so update the layers order array.*/
/* -------------------------------------------------------------------- */
for (i=0; i<nElements; i++) {
self->layerorder[i] = panIndexes[i];
}
return 1;
}
return 0;
}
/* =========================================================================
msMapLoadOWSParameters
Function to support mapscript mapObj::loadOWSParameters
========================================================================= */
int msMapLoadOWSParameters(mapObj *map, cgiRequestObj *request,
const char *wmtver)
{
#ifdef USE_WMS_SVR
int version;
char *wms_exception_format = NULL;
const char *wms_request= NULL;
int result, i = 0;
owsRequestObj ows_request;
ows_request.numlayers = 0;
ows_request.enabled_layers = NULL;
version = msOWSParseVersionString(wmtver);
for(i=0; i<request->NumParams; i++) {
if (strcasecmp(request->ParamNames[i], "EXCEPTIONS") == 0)
wms_exception_format = request->ParamValues[i];
else if (strcasecmp(request->ParamNames[i], "REQUEST") == 0)
wms_request = request->ParamValues[i];
}
msOWSRequestLayersEnabled(map, "M", wms_request, &ows_request);
result = msWMSLoadGetMapParams(map, version, request->ParamNames,
request->ParamValues, request->NumParams, wms_exception_format,
wms_request, &ows_request);
if (ows_request.numlayers > 0)
msFree(ows_request.enabled_layers);
return result;
#else
msSetError(MS_WMSERR, "WMS server support is not available.",
"msMapLoadOWSParameters()");
return MS_FAILURE;
#endif
}
Jump to Line
Something went wrong with that request. Please try again.