/********************************************************************** * $Id: mapogcsld.c,v 1.22 2004/02/12 16:01:06 assefa Exp $ * * Name: mapogcsld.c * Project: MapServer * Language: C * Purpose: OGC SLD implementation * Author: Y. Assefa, DM Solutions Group (assefa@dmsolutions.ca) * ********************************************************************** * Copyright (c) 2003, Y. Assefa, DM Solutions Group Inc * * 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 or substantial portions of the 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. ********************************************************************** * $Log: mapogcsld.c,v $ * Revision 1.22 2004/02/12 16:01:06 assefa * Test missing in Generate SLD for annotation layers. * * Revision 1.21 2004/02/11 20:47:18 assefa * Use first the wms_name metadata as the name of the NamedLayer. * If not available, use the layer's name. * * Revision 1.20 2004/02/09 22:02:33 assefa * Forgot to remove debug statements. * * Revision 1.19 2004/02/09 21:42:02 assefa * Add RasterSymbolizer support. * * Revision 1.18 2004/02/06 02:23:01 assefa * Make sure that point symbolizers always initialize the color * parameter of the style. * * Revision 1.17 2004/02/03 23:48:22 assefa * Correct a bug in msSLDApplySLD. * * Revision 1.16 2004/01/07 19:02:53 assefa * Correct return value on applysld functions. * Add ifdef in functions using libcurl related functions (httpxxx). * * Revision 1.15 2004/01/05 21:17:53 assefa * ApplySLD and ApplySLDURL on a layer can now take a NamedLayer name as argument. * * Revision 1.14 2003/12/18 18:58:55 assefa * Use the symol name instead of the id for newly created symbols. * * Revision 1.13 2003/12/17 04:16:15 frank * added ifdef USE_OGR around include of cpl_string.h * * Revision 1.12 2003/12/11 05:12:27 assefa * Remove unused variables. * * Revision 1.11 2003/12/10 20:56:17 assefa * Generate default symbol (square) when having an "invalid" symbol. * * Revision 1.10 2003/12/10 17:36:03 assefa * Add partly support for Expressions. * Correct bug with symbol outline. * * Revision 1.9 2003/12/05 04:02:33 assefa * Add generation of SLD for points and text. * * Revision 1.8 2003/12/03 18:52:21 assefa * Add partly support for SLD generation. * * Revision 1.7 2003/12/01 16:10:13 assefa * Add #ifdef USE_OGR for sld functions available to mapserver. * * Revision 1.6 2003/11/30 16:30:04 assefa * Support mulitple symbolisers in a Rule. * * Revision 1.5 2003/11/27 15:04:30 assefa * Remove unused varaibeles. * * Revision 1.4 2003/11/27 13:57:09 assefa * Add min/max scale. * * Revision 1.3 2003/11/25 03:21:44 assefa * Add test support. * Add filter support. * * Revision 1.2 2003/11/07 21:35:07 assefa * Add PointSymbolizer. * Add External Graphic symbol support. * * Revision 1.1 2003/11/06 23:09:25 assefa * OGC SLD support. * * **********************************************************************/ #include "mapogcsld.h" #include "mapogcfilter.h" #include "map.h" #ifdef USE_OGR #include "cpl_string.h" #endif #define SLD_LINE_SYMBOL_NAME "sld_line_symbol" #define SLD_LINE_SYMBOL_DASH_NAME "sld_line_symbol_dash" #define SLD_MARK_SYMBOL_SQUARE "sld_mark_symbol_square" #define SLD_MARK_SYMBOL_SQUARE_FILLED "sld_mark_symbol_square_filled" #define SLD_MARK_SYMBOL_CIRCLE "sld_mark_symbol_circle" #define SLD_MARK_SYMBOL_CIRCLE_FILLED "sld_mark_symbol_circle_filled" #define SLD_MARK_SYMBOL_TRIANGLE "sld_mark_symbol_triangle" #define SLD_MARK_SYMBOL_TRIANGLE_FILLED "sld_mark_symbol_triangle_filled" #define SLD_MARK_SYMBOL_STAR "sld_mark_symbol_star" #define SLD_MARK_SYMBOL_STAR_FILLED "sld_mark_symbol_star_filled" #define SLD_MARK_SYMBOL_CROSS "sld_mark_symbol_cross" #define SLD_MARK_SYMBOL_CROSS_FILLED "sld_mark_symbol_cross_filled" #define SLD_MARK_SYMBOL_X "sld_mark_symbol_x" #define SLD_MARK_SYMBOL_X_FILLED "sld_mark_symbol_x_filled" /************************************************************************/ /* msSLDApplySLDURL */ /* */ /* Use the SLD document given through a URL and apply the SLD */ /* on the map. Layer name and Named Layer's name parameter are */ /* used to do the match. */ /************************************************************************/ int msSLDApplySLDURL(mapObj *map, char *szURL, int iLayer, char *pszStyleLayerName) { #ifdef USE_OGR //needed for libcurl function msHTTPGetFile in maphttp.c #if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) char *pszSLDTmpFile = NULL; int status = 0; char *pszSLDbuf=NULL; FILE *fp = NULL; int nStatus = MS_FAILURE; if (map && szURL) { pszSLDTmpFile = msTmpFile(map->web.imagepath, "sld.xml"); if (msHTTPGetFile(szURL, pszSLDTmpFile, &status,-1, 0, 0) == MS_SUCCESS) { if ((fp = fopen(pszSLDTmpFile, "r")) != NULL) { int nBufsize=0; fseek(fp, 0, SEEK_END); nBufsize = ftell(fp); rewind(fp); pszSLDbuf = (char*)malloc((nBufsize+1)*sizeof(char)); fread(pszSLDbuf, 1, nBufsize, fp); pszSLDbuf[nBufsize] = '\0'; } } if (pszSLDbuf) nStatus = msSLDApplySLD(map, pszSLDbuf, iLayer, pszStyleLayerName); } return nStatus; #else msSetError(MS_MISCERR, "WMS/WFS client support is not enabled .", "msSLDApplySLDURL()"); return(MS_FAILURE); #endif #else /* ------------------------------------------------------------------ * OGR Support not included... * ------------------------------------------------------------------ */ msSetError(MS_MISCERR, "OGR support is not available.", "msSLDApplySLDURL()"); return(MS_FAILURE); #endif /* USE_OGR */ } /************************************************************************/ /* msSLDApplySLD */ /* */ /* Parses the SLD into array of layers. Go through the map and */ /* compare the SLD layers and the map layers using the name. If */ /* they have the same name, copy the classes asscoaited with */ /* the SLD layers onto the map layers. */ /************************************************************************/ int msSLDApplySLD(mapObj *map, char *psSLDXML, int iLayer, char *pszStyleLayerName) { #ifdef USE_OGR int nLayers = 0; layerObj *pasLayers = NULL; int i, j, k, iClass; int bUseSpecificLayer = 0; int bSuccess =0; char *pszTmp = NULL; pasLayers = msSLDParseSLD(map, psSLDXML, &nLayers); if (pasLayers && nLayers > 0) { for (i=0; inumlayers; i++) { if (iLayer >=0 && iLayer< map->numlayers) { i = iLayer; bUseSpecificLayer = 1; } /* compare layer name to wms_name as well */ pszTmp = msLookupHashTable(map->layers[i].metadata, "wms_name"); for (j=0; jlayers[i].name, pasLayers[j].name) == 0 || strcasecmp(pszTmp, pasLayers[j].name) == 0)) || (bUseSpecificLayer && pszStyleLayerName && (strcasecmp(pasLayers[j].name, pszStyleLayerName) == 0 || strcasecmp(pszTmp, pasLayers[j].name) == 0)) ) { bSuccess =1; /* -------------------------------------------------------------------- */ /* copy classes in reverse order : the Rule priority is the */ /* first rule is the most important (mapserver uses the painter */ /* model) */ /* -------------------------------------------------------------------- */ map->layers[i].type = pasLayers[j].type; map->layers[i].numclasses = 0; iClass = 0; for (k=pasLayers[j].numclasses-1; k>=0; k--) { initClass(&map->layers[i].class[iClass]); msCopyClass(&map->layers[i].class[iClass], &pasLayers[j].class[k], NULL); map->layers[i].class[iClass].layer = &map->layers[i]; map->layers[i].class[iClass].type = map->layers[i].type; map->layers[i].numclasses++; iClass++; } if (pasLayers[j].labelitem) { if (map->layers[i].labelitem) free(map->layers[i].labelitem); map->layers[i].labelitem = strdup(pasLayers[j].labelitem); } if (pasLayers[j].classitem) { if (map->layers[i].classitem) free(map->layers[i].classitem); map->layers[i].classitem = strdup(pasLayers[j].classitem); } /* mark as auto-generate SLD */ msInsertHashTable( map->layers[i].metadata, "wms_sld_body", "auto" ); break; } } if (bUseSpecificLayer) break; } } if (bSuccess) return MS_SUCCESS; return(MS_FAILURE); #else /* ------------------------------------------------------------------ * OGR Support not included... * ------------------------------------------------------------------ */ msSetError(MS_MISCERR, "OGR support is not available.", "msSLDApplySLD()"); return(MS_FAILURE); #endif /* USE_OGR */ } #ifdef USE_OGR /************************************************************************/ /* msSLDParseSLD */ /* */ /* Parse the sld document into layers : for each named layer */ /* there is one mapserver layer created with approproate */ /* classes and styles. */ /* Returns an array of mapserver layers. The pnLayres if */ /* provided will indicate the size of the returned array. */ /************************************************************************/ layerObj *msSLDParseSLD(mapObj *map, char *psSLDXML, int *pnLayers) { CPLXMLNode *psRoot = NULL; CPLXMLNode *psSLD, *psNamedLayer, *psChild, *psName; layerObj *pasLayers = NULL; int iLayer = 0; int nLayers = 0; if (map == NULL || psSLDXML == NULL || strlen(psSLDXML) <= 0 || (strstr(psSLDXML, "StyledLayerDescriptor") == NULL)) { msSetError(MS_WMSERR, "Invalid SLD document", ""); return NULL; } psRoot = CPLParseXMLString(psSLDXML); if( psRoot == NULL) { msSetError(MS_WMSERR, "Invalid SLD document", ""); return NULL; } //strip namespaces ogc and sld and gml CPLStripXMLNamespace(psRoot, "ogc", 1); CPLStripXMLNamespace(psRoot, "sld", 1); CPLStripXMLNamespace(psRoot, "gml", 1); /* -------------------------------------------------------------------- */ /* get the root element (Filter). */ /* -------------------------------------------------------------------- */ psChild = psRoot; psSLD = NULL; while( psChild != NULL ) { if (psChild->eType == CXT_Element && EQUAL(psChild->pszValue,"StyledLayerDescriptor")) { psSLD = psChild; break; } else psChild = psChild->psNext; } if (!psSLD) { msSetError(MS_WMSERR, "Invalid SLD document", ""); return NULL; } /* -------------------------------------------------------------------- */ /* Parse the named layers. */ /* -------------------------------------------------------------------- */ psNamedLayer = CPLGetXMLNode(psSLD, "NamedLayer"); while (psNamedLayer && psNamedLayer->pszValue && strcasecmp(psNamedLayer->pszValue, "NamedLayer") == 0) { psNamedLayer = psNamedLayer->psNext; nLayers++; } if (nLayers > 0) pasLayers = (layerObj *)malloc(sizeof(layerObj)*nLayers); else return NULL; psNamedLayer = CPLGetXMLNode(psSLD, "NamedLayer"); if (psNamedLayer) { iLayer = 0; while (psNamedLayer && psNamedLayer->pszValue && strcasecmp(psNamedLayer->pszValue, "NamedLayer") == 0) { psName = CPLGetXMLNode(psNamedLayer, "Name"); initLayer(&pasLayers[iLayer], map); if (psName && psName->psChild && psName->psChild->pszValue) pasLayers[iLayer].name = strdup(psName->psChild->pszValue); msSLDParseNamedLayer(psNamedLayer, &pasLayers[iLayer]); psNamedLayer = psNamedLayer->psNext; iLayer++; } } if (pnLayers) *pnLayers = nLayers; if (psRoot) CPLDestroyXMLNode(psRoot); return pasLayers; } /************************************************************************/ /* msSLDParseNamedLayer */ /* */ /* Parse NamedLayer root. */ /************************************************************************/ void msSLDParseNamedLayer(CPLXMLNode *psRoot, layerObj *psLayer) { CPLXMLNode *psFeatureTypeStyle, *psRule, *psUserStyle; CPLXMLNode *psElseFilter = NULL, *psFilter=NULL; CPLXMLNode *psMinScale=NULL, *psMaxScale=NULL; CPLXMLNode *psName=NULL, *psTitle=NULL; CPLXMLNode *psTmpNode = NULL; FilterEncodingNode *psNode = NULL; char *szExpression = NULL; char *szClassItem = NULL; int i=0, nNewClasses=0, nClassBeforeFilter=0, nClassAfterFilter=0; int nClassAfterRule=0, nClassBeforeRule=0; char *pszTmpFilter = NULL; double dfMinScale=0, dfMaxScale=0; char *pszName=NULL, *pszTitle=NULL; if (psRoot && psLayer) { psUserStyle = CPLGetXMLNode(psRoot, "UserStyle"); if (psUserStyle) { psFeatureTypeStyle = CPLGetXMLNode(psUserStyle, "FeatureTypeStyle"); if (psFeatureTypeStyle) { while (psFeatureTypeStyle && psFeatureTypeStyle->pszValue && strcasecmp(psFeatureTypeStyle->pszValue, "FeatureTypeStyle") == 0) { psRule = CPLGetXMLNode(psFeatureTypeStyle, "Rule"); /* -------------------------------------------------------------------- */ /* First parse rules with the else filter. These rules will */ /* create the classes that are placed at the end of class */ /* list. (See how classes are applied to layers in function */ /* msSLDApplySLD). */ /* -------------------------------------------------------------------- */ while (psRule && psRule->pszValue && strcasecmp(psRule->pszValue, "Rule") == 0) { psElseFilter = CPLGetXMLNode(psRule, "ElseFilter"); if (psElseFilter) msSLDParseRule(psRule, psLayer); psRule = psRule->psNext; } /* -------------------------------------------------------------------- */ /* Parse rules with no Else filter. */ /* -------------------------------------------------------------------- */ psRule = CPLGetXMLNode(psFeatureTypeStyle, "Rule"); while (psRule && psRule->pszValue && strcasecmp(psRule->pszValue, "Rule") == 0) { //used for scale setting nClassBeforeRule = psLayer->numclasses; psElseFilter = CPLGetXMLNode(psRule, "ElseFilter"); nClassBeforeFilter = psLayer->numclasses; if (psElseFilter == NULL) msSLDParseRule(psRule, psLayer); nClassAfterFilter = psLayer->numclasses; /* -------------------------------------------------------------------- */ /* Parse the filter and apply it to the latest class created by */ /* the rule. */ /* NOTE : Spatial Filter is not supported. */ /* -------------------------------------------------------------------- */ psFilter = CPLGetXMLNode(psRule, "Filter"); if (psFilter && psFilter->psChild && psFilter->psChild->pszValue) { //clone the tree and set the next node to null //so we only have the Filter node psTmpNode = CPLCloneXMLTree(psFilter); psTmpNode->psNext = NULL; pszTmpFilter = CPLSerializeXMLTree(psTmpNode); CPLDestroyXMLNode(psTmpNode); if (pszTmpFilter) { //nTmp = strlen(psFilter->psChild->pszValue)+17; //pszTmpFilter = malloc(sizeof(char)*nTmp); //sprintf(pszTmpFilter,"%s", // psFilter->psChild->pszValue); //pszTmpFilter[nTmp-1]='\0'; psNode = FLTParseFilterEncoding(pszTmpFilter); CPLFree(pszTmpFilter); } if (psNode) { szExpression = FLTGetMapserverExpression(psNode); if (szExpression) { szClassItem = FLTGetMapserverExpressionClassItem(psNode); nNewClasses = nClassAfterFilter - nClassBeforeFilter; for (i=0; i class[psLayer->numclasses-1-i]. expression, szExpression); } if (szClassItem) psLayer->classitem = strdup(szClassItem); } } } /* -------------------------------------------------------------------- */ /* parse minscale and maxscale. */ /* -------------------------------------------------------------------- */ psMinScale = CPLGetXMLNode(psRule, "MinScaleDenominator"); if (psMinScale && psMinScale->psChild && psMinScale->psChild->pszValue) dfMinScale = atof(psMinScale->psChild->pszValue); psMaxScale = CPLGetXMLNode(psRule, "MaxScaleDenominator"); if (psMaxScale && psMaxScale->psChild && psMaxScale->psChild->pszValue) dfMaxScale = atof(psMaxScale->psChild->pszValue); /* -------------------------------------------------------------------- */ /* parse name and title. */ /* -------------------------------------------------------------------- */ psName = CPLGetXMLNode(psRule, "Name"); if (psName && psName->psChild && psName->psChild->pszValue) pszName = psName->psChild->pszValue; psTitle = CPLGetXMLNode(psRule, "Title"); if (psTitle && psTitle->psChild && psTitle->psChild->pszValue) pszTitle = psTitle->psChild->pszValue; nClassAfterRule = psLayer->numclasses; /* -------------------------------------------------------------------- */ /* set the scale to all the classes created by the rule. */ /* -------------------------------------------------------------------- */ if (dfMinScale > 0 || dfMaxScale > 0) { nNewClasses = nClassAfterRule - nClassBeforeRule; for (i=0; i 0) psLayer->class[psLayer->numclasses-1-i].minscale = dfMinScale; if (dfMaxScale) psLayer->class[psLayer->numclasses-1-i].maxscale = dfMaxScale; } } /* -------------------------------------------------------------------- */ /* set name and title to the classes created by the rule. */ /* -------------------------------------------------------------------- */ if (pszName || pszTitle) { nNewClasses = nClassAfterRule - nClassBeforeRule; for (i=0; iclass[psLayer->numclasses-1-i].name = strdup(pszName); if (pszTitle) psLayer->class[psLayer->numclasses-1-i].title = strdup(pszTitle); } } //TODO : parse legendgraphic psRule = psRule->psNext; } psFeatureTypeStyle = psFeatureTypeStyle->psNext; } } } } } /************************************************************************/ /* void msSLDParseRule(CPLXMLNode *psRoot, layerObj *psLayer) */ /* */ /* Parse a Rule node into classes for a spcific layer. */ /************************************************************************/ void msSLDParseRule(CPLXMLNode *psRoot, layerObj *psLayer) { CPLXMLNode *psLineSymbolizer = NULL; CPLXMLNode *psPolygonSymbolizer = NULL; CPLXMLNode *psPointSymbolizer = NULL; CPLXMLNode *psTextSymbolizer = NULL; CPLXMLNode *psRasterSymbolizer = NULL; CPLXMLNode *psMaxScale=NULL, *psMinScale=NULL; int i = 0; int bSymbolizer = 0; int bNewClass=0, nSymbolizer=0; if (psRoot && psLayer) { //TODO : parse name of the rule /* -------------------------------------------------------------------- */ /* The SLD specs assumes here that a certain FeatureType can only have*/ /* rules for only one type of symbolizer. */ /* -------------------------------------------------------------------- */ /* ==================================================================== */ /* For each rule a new class is created. If there are more than */ /* one symbolizer of the same type, a style is added in the */ /* same class. */ /* ==================================================================== */ //line symbolizer psLineSymbolizer = CPLGetXMLNode(psRoot, "LineSymbolizer"); nSymbolizer =0; while (psLineSymbolizer && psLineSymbolizer->pszValue && strcasecmp(psLineSymbolizer->pszValue, "LineSymbolizer") == 0) { bSymbolizer = 1; if (nSymbolizer == 0) bNewClass = 1; else bNewClass = 0; msSLDParseLineSymbolizer(psLineSymbolizer, psLayer, bNewClass); psLineSymbolizer = psLineSymbolizer->psNext; psLayer->type = MS_LAYER_LINE; nSymbolizer++; } //Polygon symbolizer psPolygonSymbolizer = CPLGetXMLNode(psRoot, "PolygonSymbolizer"); nSymbolizer =0; while (psPolygonSymbolizer && psPolygonSymbolizer->pszValue && strcasecmp(psPolygonSymbolizer->pszValue, "PolygonSymbolizer") == 0) { bSymbolizer = 1; if (nSymbolizer == 0) bNewClass = 1; else bNewClass = 0; msSLDParsePolygonSymbolizer(psPolygonSymbolizer, psLayer, bNewClass); psPolygonSymbolizer = psPolygonSymbolizer->psNext; psLayer->type = MS_LAYER_POLYGON; nSymbolizer++; } //Point Symbolizer psPointSymbolizer = CPLGetXMLNode(psRoot, "PointSymbolizer"); nSymbolizer =0; while (psPointSymbolizer && psPointSymbolizer->pszValue && strcasecmp(psPointSymbolizer->pszValue, "PointSymbolizer") == 0) { bSymbolizer = 1; if (nSymbolizer == 0) bNewClass = 1; else bNewClass = 0; msSLDParsePointSymbolizer(psPointSymbolizer, psLayer, bNewClass); psPointSymbolizer = psPointSymbolizer->psNext; psLayer->type = MS_LAYER_POINT; nSymbolizer++; } //Text symbolizer /* ==================================================================== */ /* For text symbolizer, here is how it is translated into */ /* mapserver classes : */ /* - If there are other symbolizers(line, polygon, symbol), */ /* the label object created will be created in the same class */ /* (the last class) as the symbolizer. This allows o have for */ /* example of point layer with labels. */ /* - If there are no other symbolizers, a new clas will be */ /* created ocontain the label object. */ /* ==================================================================== */ psTextSymbolizer = CPLGetXMLNode(psRoot, "TextSymbolizer"); while (psTextSymbolizer && psTextSymbolizer->pszValue && strcasecmp(psTextSymbolizer->pszValue, "TextSymbolizer") == 0) { if (nSymbolizer == 0) psLayer->type = MS_LAYER_ANNOTATION; msSLDParseTextSymbolizer(psTextSymbolizer, psLayer, bSymbolizer); psTextSymbolizer = psTextSymbolizer->psNext; } //Raster symbolizer psRasterSymbolizer = CPLGetXMLNode(psRoot, "RasterSymbolizer"); while (psRasterSymbolizer && psRasterSymbolizer->pszValue && strcasecmp(psRasterSymbolizer->pszValue, "RasterSymbolizer") == 0) { msSLDParseRasterSymbolizer(psRasterSymbolizer, psLayer); psRasterSymbolizer = psRasterSymbolizer->psNext; psLayer->type = MS_LAYER_RASTER; } /* -------------------------------------------------------------------- */ /* Parse the minscale and maxscale and applt it to all classes */ /* in the layer. */ /* -------------------------------------------------------------------- */ psMinScale = CPLGetXMLNode(psRoot, "MinScaleDenominator"); if (psMinScale && psMinScale->psChild && psMinScale->psChild->pszValue) { for (i=0; inumclasses; i++) psLayer->class[i].minscale = atof(psMinScale->psChild->pszValue); } psMaxScale = CPLGetXMLNode(psRoot, "MaxScaleDenominator"); if (psMaxScale && psMaxScale->psChild && psMaxScale->psChild->pszValue) { for (i=0; inumclasses; i++) psLayer->class[i].maxscale = atof(psMaxScale->psChild->pszValue); } } } /************************************************************************/ /* void msSLDParseLineSymbolizer(CPLXMLNode *psRoot, layerObj */ /* *psLayer) */ /* */ /* Parses the LineSymbolizer rule and creates a class in the */ /* layer. */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* Example of a rule : */ /* ... */ /* */ /* */ /* */ /* center-line */ /* */ /* */ /* #0000ff */ /* 5.0 */ /* 10.0 5 5 10*/ /* */ /* */ /* */ /* ... */ /************************************************************************/ void msSLDParseLineSymbolizer(CPLXMLNode *psRoot, layerObj *psLayer, int bNewClass) { int nClassId = 0; CPLXMLNode *psStroke; int iStyle = 0; if (psRoot && psLayer) { psStroke = CPLGetXMLNode(psRoot, "Stroke"); if (psStroke) { if (bNewClass || psLayer->numclasses <= 0) { initClass(&(psLayer->class[psLayer->numclasses])); nClassId = psLayer->numclasses; psLayer->numclasses++; } else nClassId = psLayer->numclasses-1; iStyle = psLayer->class[nClassId].numstyles; initStyle(&(psLayer->class[nClassId].styles[iStyle])); psLayer->class[nClassId].numstyles++; msSLDParseStroke(psStroke, &psLayer->class[nClassId].styles[iStyle], psLayer->map, 0); } } } /************************************************************************/ /* void msSLDParseStroke(CPLXMLNode *psStroke, styleObj */ /* *psStyle, int iColorParam) */ /* */ /* Parse Stroke content into a style object. */ /* The iColorParm is used to indicate which color object to use */ /* : */ /* 0 : for color */ /* 1 : outlinecolor */ /* 2 : backgroundcolor */ /************************************************************************/ void msSLDParseStroke(CPLXMLNode *psStroke, styleObj *psStyle, mapObj *map, int iColorParam) { CPLXMLNode *psCssParam = NULL, *psGraphicFill=NULL; char *psStrkName = NULL; char *psColor = NULL; int nLength = 0; char *pszDashValue = NULL; if (psStroke && psStyle) { //parse css parameters psCssParam = CPLGetXMLNode(psStroke, "CssParameter"); while (psCssParam && psCssParam->pszValue && strcasecmp(psCssParam->pszValue, "CssParameter") == 0) { psStrkName = (char*)CPLGetXMLValue(psCssParam, "name", NULL); if (psStrkName) { if (strcasecmp(psStrkName, "stroke") == 0) { if(psCssParam->psChild && psCssParam->psChild->psNext && psCssParam->psChild->psNext->pszValue) psColor = psCssParam->psChild->psNext->pszValue; if (psColor) { nLength = strlen(psColor); //expecting hexadecimal ex : #aaaaff if (nLength == 7 && psColor[0] == '#') { if (iColorParam == 0) { psStyle->color.red = hex2int(psColor+1); psStyle->color.green = hex2int(psColor+3); psStyle->color.blue= hex2int(psColor+5); } else if (iColorParam == 1) { psStyle->outlinecolor.red = hex2int(psColor+1); psStyle->outlinecolor.green = hex2int(psColor+3); psStyle->outlinecolor.blue= hex2int(psColor+5); } else if (iColorParam == 2) { psStyle->backgroundcolor.red = hex2int(psColor+1); psStyle->backgroundcolor.green = hex2int(psColor+3); psStyle->backgroundcolor.blue= hex2int(psColor+5); } } } } else if (strcasecmp(psStrkName, "stroke-width") == 0) { if(psCssParam->psChild && psCssParam->psChild->psNext && psCssParam->psChild->psNext->pszValue) { psStyle->size = atoi(psCssParam->psChild->psNext->pszValue); //use an ellipse symbol for the width if (psStyle->symbol <=0) { psStyle->symbol = msSLDGetLineSymbol(map); if (psStyle->symbol > 0 && psStyle->symbol < map->symbolset.numsymbols) psStyle->symbolname = strdup(map->symbolset.symbol[psStyle->symbol].name); } } } else if (strcasecmp(psStrkName, "stroke-dasharray") == 0) { if(psCssParam->psChild && psCssParam->psChild->psNext && psCssParam->psChild->psNext->pszValue) { pszDashValue = strdup(psCssParam->psChild->psNext->pszValue); //use an ellipse symbol with dash arrays psStyle->symbol = msSLDGetDashLineSymbol(map, psCssParam->psChild->psNext->pszValue); if ( psStyle->symbol > 0 && psStyle->symbol < map->symbolset.numsymbols) psStyle->symbolname = strdup(map->symbolset.symbol[psStyle->symbol].name); } } } psCssParam = psCssParam->psNext; } //parse graphic fill or stroke //graphic fill and graphic stroke pare parsed the same way : //TODO : It seems inconsistent to me since the only diffrence //between them seems to be fill (fill) or not fill (stroke). And //then again the fill parameter can be used inside both elements. psGraphicFill = CPLGetXMLNode(psStroke, "GraphicFill"); if (psGraphicFill) msSLDParseGraphicFillOrStroke(psGraphicFill, pszDashValue, psStyle, map, 0); psGraphicFill = CPLGetXMLNode(psStroke, "GraphicStroke"); if (psGraphicFill) msSLDParseGraphicFillOrStroke(psGraphicFill, pszDashValue, psStyle, map, 0); if (pszDashValue) free(pszDashValue); } } /************************************************************************/ /* void msSLDParsePolygonSymbolizer(CPLXMLNode *psRoot, */ /* layerObj *psLayer) */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* Here, the CssParameter names are fill instead of stroke and */ /* fill-opacity instead of stroke-opacity. None of the other CssParameters*/ /* in Stroke are available for filling and the default value for the fill color in this context is 50% gray (value #808080).*/ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* The default if neither an ExternalGraphic nor a Mark is specified is to use the default*/ /* mark of a square with a 50%-gray fill and a black outline, with a size of 6 pixels.*/ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* The WellKnownName element gives the well-known name of the shape of the mark.*/ /* Allowed values include at least square, circle, triangle, star, cross,*/ /* and x, though map servers may draw a different symbol instead if they don't have a*/ /* shape for all of these. The default WellKnownName is square. Renderings of these*/ /* marks may be made solid or hollow depending on Fill and Stroke elements.*/ /* */ /************************************************************************/ void msSLDParsePolygonSymbolizer(CPLXMLNode *psRoot, layerObj *psLayer, int bNewClass) { CPLXMLNode *psFill, *psStroke; int nClassId=0, iStyle=0; if (psRoot && psLayer) { psFill = CPLGetXMLNode(psRoot, "Fill"); if (psFill) { if (bNewClass || psLayer->numclasses <= 0) { initClass(&(psLayer->class[psLayer->numclasses])); nClassId = psLayer->numclasses; psLayer->numclasses++; } else nClassId = psLayer->numclasses-1; iStyle = psLayer->class[nClassId].numstyles; initStyle(&(psLayer->class[nClassId].styles[iStyle])); psLayer->class[nClassId].numstyles++; msSLDParsePolygonFill(psFill, &psLayer->class[nClassId].styles[iStyle], psLayer->map); } //stroke wich corresponds to the outilne in mapserver //is drawn after the fill psStroke = CPLGetXMLNode(psRoot, "Stroke"); if (psStroke) { /* -------------------------------------------------------------------- */ /* there was a fill so add a style to the last class created */ /* by the fill */ /* -------------------------------------------------------------------- */ if (psFill && psLayer->numclasses > 0) { nClassId =psLayer->numclasses-1; iStyle = psLayer->class[nClassId].numstyles; initStyle(&(psLayer->class[nClassId].styles[iStyle])); psLayer->class[nClassId].numstyles++; } else { if (bNewClass || psLayer->numclasses <= 0) { initClass(&(psLayer->class[psLayer->numclasses])); nClassId = psLayer->numclasses; psLayer->numclasses++; } else nClassId = psLayer->numclasses-1; iStyle = psLayer->class[nClassId].numstyles; initStyle(&(psLayer->class[nClassId].styles[iStyle])); psLayer->class[nClassId].numstyles++; } msSLDParseStroke(psStroke, &psLayer->class[nClassId].styles[iStyle], psLayer->map, 1); } } } /************************************************************************/ /* void msSLDParsePolygonFill(CPLXMLNode *psFill, styleObj *psStyle, */ /* mapObj *map) */ /* */ /* Parse the Fill node for a polygon into a style. */ /************************************************************************/ void msSLDParsePolygonFill(CPLXMLNode *psFill, styleObj *psStyle, mapObj *map) { CPLXMLNode *psCssParam, *psGraphicFill; char *psColor=NULL, *psFillName=NULL; int nLength = 0; if (psFill && psStyle && map) { //sets the default fill color defined in the spec #808080 psStyle->color.red = 128; psStyle->color.green = 128; psStyle->color.blue = 128; psCssParam = CPLGetXMLNode(psFill, "CssParameter"); while (psCssParam && psCssParam->pszValue && strcasecmp(psCssParam->pszValue, "CssParameter") == 0) { psFillName = (char*)CPLGetXMLValue(psCssParam, "name", NULL); if (psFillName) { if (strcasecmp(psFillName, "fill") == 0) { if(psCssParam->psChild && psCssParam->psChild->psNext && psCssParam->psChild->psNext->pszValue) psColor = psCssParam->psChild->psNext->pszValue; if (psColor) { nLength = strlen(psColor); //expecting hexadecimal ex : #aaaaff if (nLength == 7 && psColor[0] == '#') { psStyle->color.red = hex2int(psColor+1); psStyle->color.green = hex2int(psColor+3); psStyle->color.blue= hex2int(psColor+5); } } } } psCssParam = psCssParam->psNext; } //graphic fill and graphic stroke pare parsed the same way : //TODO : It seems inconsistent to me since the only diffrence //between them seems to be fill (fill) or not fill (stroke). And //then again the fill parameter can be used inside both elements. psGraphicFill = CPLGetXMLNode(psFill, "GraphicFill"); if (psGraphicFill) msSLDParseGraphicFillOrStroke(psGraphicFill, NULL, psStyle, map, 0); psGraphicFill = CPLGetXMLNode(psFill, "GraphicStroke"); if (psGraphicFill) msSLDParseGraphicFillOrStroke(psGraphicFill, NULL, psStyle, map, 0); } } /************************************************************************/ /* msSLDParseGraphicFillOrStroke */ /* */ /* Parse the GraphicFill Or GraphicStroke node : look for a */ /* Merker symbol and set the style for that symbol. */ /************************************************************************/ void msSLDParseGraphicFillOrStroke(CPLXMLNode *psRoot, char *pszDashValue, styleObj *psStyle, mapObj *map, int bPointLayer) { CPLXMLNode *psCssParam, *psGraphic, *psExternalGraphic, *psMark, *psSize; CPLXMLNode *psWellKnownName, *psStroke, *psFill; char *psColor=NULL, *psColorName = NULL; int nLength = 0; char *pszSymbolName = NULL; int bFilled = 0, bStroked=0; if (psRoot && psStyle && map) { /* ==================================================================== */ /* This a definition taken from the specification (11.3.2) : */ /* Graphics can either be referenced from an external URL in a common format (such as*/ /* GIF or SVG) or may be derived from a Mark. Multiple external URLs and marks may be*/ /* referenced with the semantic that they all provide the equivalent graphic in different*/ /* formats. */ /* */ /* For this reason, we only need to support one Mark and one */ /* ExtrnalGraphic ???? */ /* ==================================================================== */ psGraphic = CPLGetXMLNode(psRoot, "Graphic"); if (psGraphic) { //extract symbol size psSize = CPLGetXMLNode(psGraphic, "Size"); if (psSize && psSize->psChild && psSize->psChild->pszValue) psStyle->size = atoi(psSize->psChild->pszValue); else psStyle->size = 6; //defualt value //extract symbol psMark = CPLGetXMLNode(psGraphic, "Mark"); if (psMark) { pszSymbolName = NULL; psWellKnownName = CPLGetXMLNode(psMark, "WellKnownName"); if (psWellKnownName && psWellKnownName->psChild && psWellKnownName->psChild->pszValue) pszSymbolName = strdup(psWellKnownName->psChild->pszValue); //default symbol is square if (!pszSymbolName || (strcasecmp(pszSymbolName, "square") != 0 && strcasecmp(pszSymbolName, "circle") != 0 && strcasecmp(pszSymbolName, "triangle") != 0 && strcasecmp(pszSymbolName, "star") != 0 && strcasecmp(pszSymbolName, "cross") != 0 && strcasecmp(pszSymbolName, "x") != 0)) pszSymbolName = strdup("square"); //check if the symbol should be filled or not psFill = CPLGetXMLNode(psMark, "Fill"); psStroke = CPLGetXMLNode(psMark, "Stroke"); if (psFill || psStroke) { if (psFill) bFilled = 1; else bFilled = 0; if (psStroke) bStroked = 1; else bStroked = 0; if (psFill) { psCssParam = CPLGetXMLNode(psFill, "CssParameter"); while (psCssParam && psCssParam->pszValue && strcasecmp(psCssParam->pszValue, "CssParameter") == 0) { psColorName = (char*)CPLGetXMLValue(psCssParam, "name", NULL); if (psColorName && strcasecmp(psColorName, "fill") == 0) { if(psCssParam->psChild && psCssParam->psChild->psNext && psCssParam->psChild->psNext->pszValue) psColor = psCssParam->psChild->psNext->pszValue; if (psColor) { nLength = strlen(psColor); if (nLength == 7 && psColor[0] == '#') { msSLDSetColorObject(psColor, &psStyle->color); } } break; } psCssParam = psCssParam->psNext; } } if (psStroke) { psCssParam = CPLGetXMLNode(psStroke, "CssParameter"); while (psCssParam && psCssParam->pszValue && strcasecmp(psCssParam->pszValue, "CssParameter") == 0) { psColorName = (char*)CPLGetXMLValue(psCssParam, "name", NULL); if (psColorName && strcasecmp(psColorName, "stroke") == 0) { if(psCssParam->psChild && psCssParam->psChild->psNext && psCssParam->psChild->psNext->pszValue) psColor = psCssParam->psChild->psNext->pszValue; if (psColor) { nLength = strlen(psColor); if (nLength == 7 && psColor[0] == '#') { //we should set the color for point layers since the //outline color is not used when //rendering symbols if (bPointLayer) msSLDSetColorObject(psColor, &psStyle->color); else msSLDSetColorObject(psColor, &psStyle->outlinecolor); } } break; } psCssParam = psCssParam->psNext; } } //set the default color if color is not not already set if ((psStyle->color.red < 0 || psStyle->color.green == -1 || psStyle->color.blue == -1) && (psStyle->outlinecolor.red == -1 || psStyle->outlinecolor.green == -1 || psStyle->outlinecolor.blue == -1)) { psStyle->color.red = 128; psStyle->color.green = 128; psStyle->color.blue = 128; } } //Get the corresponding symbol id psStyle->symbol = msSLDGetMarkSymbol(map, pszSymbolName, bFilled, pszDashValue); if (psStyle->symbol > 0 && psStyle->symbol < map->symbolset.numsymbols) psStyle->symbolname = strdup(map->symbolset.symbol[psStyle->symbol].name); } else { psExternalGraphic = CPLGetXMLNode(psGraphic, "ExternalGraphic"); if (psExternalGraphic) msSLDParseExternalGraphic(psExternalGraphic, psStyle, map); } } } } /************************************************************************/ /* int msSLDGetLineSymbol(mapObj *map) */ /* */ /* Returns a symbol id for SLD_LINE_SYMBOL_NAME used for line */ /* with. If the symbol does not exist, cretaes it an inmap */ /* symbol. */ /************************************************************************/ int msSLDGetLineSymbol(mapObj *map) { int nSymbolId = 0; symbolObj *psSymbol = NULL; /* -------------------------------------------------------------------- */ /* If the symbol exists, return it. We will use the same */ /* ellipse symbol for all the line width needs in the SLD. */ /* -------------------------------------------------------------------- */ nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_LINE_SYMBOL_NAME); if (nSymbolId >= 0) return nSymbolId; if(map->symbolset.numsymbols == MS_MAXSYMBOLS) { msSetError(MS_SYMERR, "Too many symbols defined.", "msSLDGetLineSymbol()"); return 0; //returs 0 for no symbol } psSymbol = &map->symbolset.symbol[map->symbolset.numsymbols]; map->symbolset.numsymbols++; /* -------------------------------------------------------------------- */ /* Create an ellipse symbol to be used for lines : */ /* NAME 'dashed' */ /* TYPE ELLIPSE */ /* POINTS 1 1 END */ /* FILLED true */ /* -------------------------------------------------------------------- */ initSymbol(psSymbol); psSymbol->inmapfile = MS_TRUE; psSymbol->name = strdup(SLD_LINE_SYMBOL_NAME); psSymbol->type = MS_SYMBOL_ELLIPSE; psSymbol->filled = MS_TRUE; psSymbol->points[psSymbol->numpoints].x = 1; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->sizex = 1; psSymbol->sizey = 1; psSymbol->numpoints ++; return map->symbolset.numsymbols-1; } /************************************************************************/ /* int msSLDGetDashLineSymbol(mapObj *map, char *pszDashArray) */ /* */ /* Create a dash line inmap symbol. */ /************************************************************************/ int msSLDGetDashLineSymbol(mapObj *map, char *pszDashArray) { symbolObj *psSymbol = NULL; char **aszValues = NULL; int nDash, i; if(map->symbolset.numsymbols == MS_MAXSYMBOLS) { msSetError(MS_SYMERR, "Too many symbols defined.", "msSLDGetDashLineSymbol()"); return 0; //returs 0 for no symbol } psSymbol = &map->symbolset.symbol[map->symbolset.numsymbols]; map->symbolset.numsymbols++; /* -------------------------------------------------------------------- */ /* Create an ellipse symbol to be used for lines : */ /* NAME 'dashed' */ /* TYPE ELLIPSE */ /* POINTS 1 1 END */ /* FILLED true */ /* STYLE dashline value */ /* -------------------------------------------------------------------- */ initSymbol(psSymbol); psSymbol->inmapfile = MS_TRUE; psSymbol->name = strdup(SLD_LINE_SYMBOL_DASH_NAME); psSymbol->type = MS_SYMBOL_ELLIPSE; psSymbol->filled = MS_TRUE; psSymbol->points[psSymbol->numpoints].x = 1; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->sizex = 1; psSymbol->sizey = 1; psSymbol->numpoints++; if (pszDashArray) { nDash = 0; aszValues = split(pszDashArray, ' ', &nDash); if (nDash > 0) { psSymbol->stylelength = nDash; for (i=0; istyle[i] = atoi(aszValues[i]); msFreeCharArray(aszValues, nDash); } } return map->symbolset.numsymbols-1; } /************************************************************************/ /* msSLDGetMarkSymbol */ /* */ /* Get a Mark symbol using the name. Mark symbols can be */ /* square, circle, triangle, star, cross, x. */ /* If the symbol does not exsist add it to the symbol list. */ /************************************************************************/ int msSLDGetMarkSymbol(mapObj *map, char *pszSymbolName, int bFilled, char *pszDashValue) { int nSymbolId = 0; char **aszValues = NULL; int nDash, i; symbolObj *psSymbol = NULL; if (!map || !pszSymbolName) return 0; if (strcasecmp(pszSymbolName, "square") == 0) { if (bFilled) nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_SQUARE_FILLED); else nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_SQUARE); } else if (strcasecmp(pszSymbolName, "circle") == 0) { if (bFilled) nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_CIRCLE_FILLED); else nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_CIRCLE); } else if (strcasecmp(pszSymbolName, "triangle") == 0) { if (bFilled) nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_TRIANGLE_FILLED); else nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_TRIANGLE); } else if (strcasecmp(pszSymbolName, "star") == 0) { if (bFilled) nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_STAR_FILLED); else nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_STAR); } else if (strcasecmp(pszSymbolName, "cross") == 0) { if (bFilled) nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_CROSS_FILLED); else nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_CROSS); } else if (strcasecmp(pszSymbolName, "x") == 0) { if (bFilled) nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_X_FILLED); else nSymbolId = msGetSymbolIndex(&map->symbolset, SLD_MARK_SYMBOL_X); } if (nSymbolId <= 0) { if(map->symbolset.numsymbols == MS_MAXSYMBOLS) { msSetError(MS_SYMERR, "Too many symbols defined.", "msSLDGetMarkSymbol()"); return 0; //returs 0 for no symbol } psSymbol = &map->symbolset.symbol[map->symbolset.numsymbols]; nSymbolId = map->symbolset.numsymbols; map->symbolset.numsymbols++; initSymbol(psSymbol); psSymbol->inmapfile = MS_TRUE; psSymbol->sizex = 1; psSymbol->sizey = 1; if (pszDashValue) { nDash = 0; aszValues = split(pszDashValue, ' ', &nDash); if (nDash > 0) { psSymbol->stylelength = nDash; for (i=0; istyle[i] = atoi(aszValues[i]); msFreeCharArray(aszValues, nDash); } } if (strcasecmp(pszSymbolName, "square") == 0) { if (bFilled) psSymbol->name = strdup(SLD_MARK_SYMBOL_SQUARE_FILLED); else psSymbol->name = strdup(SLD_MARK_SYMBOL_SQUARE); psSymbol->type = MS_SYMBOL_VECTOR; if (bFilled) psSymbol->filled = MS_TRUE; psSymbol->points[psSymbol->numpoints].x = 0; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0; psSymbol->points[psSymbol->numpoints].y = 0; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 1; psSymbol->points[psSymbol->numpoints].y = 0; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 1; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->numpoints++; } else if (strcasecmp(pszSymbolName, "circle") == 0) { if (bFilled) psSymbol->name = strdup(SLD_MARK_SYMBOL_CIRCLE_FILLED); else psSymbol->name = strdup(SLD_MARK_SYMBOL_CIRCLE); psSymbol->type = MS_SYMBOL_ELLIPSE; if (bFilled) psSymbol->filled = MS_TRUE; psSymbol->points[psSymbol->numpoints].x = 1; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->sizex = 1; psSymbol->sizey = 1; psSymbol->numpoints++; } else if (strcasecmp(pszSymbolName, "triangle") == 0) { if (bFilled) psSymbol->name = strdup(SLD_MARK_SYMBOL_TRIANGLE_FILLED); else psSymbol->name = strdup(SLD_MARK_SYMBOL_TRIANGLE); psSymbol->type = MS_SYMBOL_VECTOR; if (bFilled) psSymbol->filled = MS_TRUE; psSymbol->points[psSymbol->numpoints].x = 0; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0.5; psSymbol->points[psSymbol->numpoints].y = 0; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 1; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->numpoints++; } else if (strcasecmp(pszSymbolName, "star") == 0) { if (bFilled) psSymbol->name = strdup(SLD_MARK_SYMBOL_STAR_FILLED); else psSymbol->name = strdup(SLD_MARK_SYMBOL_STAR); psSymbol->type = MS_SYMBOL_VECTOR; if (bFilled) psSymbol->filled = MS_TRUE; psSymbol->points[psSymbol->numpoints].x = 0; psSymbol->points[psSymbol->numpoints].y = 0.375; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0.35; psSymbol->points[psSymbol->numpoints].y = 0.375; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0.5; psSymbol->points[psSymbol->numpoints].y = 0; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0.65; psSymbol->points[psSymbol->numpoints].y = 0.375; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 1; psSymbol->points[psSymbol->numpoints].y = 0.375; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0.75; psSymbol->points[psSymbol->numpoints].y = 0.625; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0.875; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0.5; psSymbol->points[psSymbol->numpoints].y = 0.75; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0.125; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0.25; psSymbol->points[psSymbol->numpoints].y = 0.625; psSymbol->numpoints++; } //cross is like plus (+) since there is also X symbol ?? else if (strcasecmp(pszSymbolName, "cross") == 0) { //NEVER FILL CROSS //if (bFilled) // psSymbol->name = strdup(SLD_MARK_SYMBOL_CROSS_FILLED); //else psSymbol->name = strdup(SLD_MARK_SYMBOL_CROSS); psSymbol->type = MS_SYMBOL_VECTOR; //if (bFilled) // psSymbol->filled = MS_TRUE; psSymbol->points[psSymbol->numpoints].x = 0.5; psSymbol->points[psSymbol->numpoints].y = 0; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0.5; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = -1; psSymbol->points[psSymbol->numpoints].y = -1; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0; psSymbol->points[psSymbol->numpoints].y = 0.5; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 1; psSymbol->points[psSymbol->numpoints].y = 0.5; psSymbol->numpoints++; } else if (strcasecmp(pszSymbolName, "x") == 0) { //NEVER FILL X //if (bFilled) // psSymbol->name = strdup(SLD_MARK_SYMBOL_X_FILLED); //else psSymbol->name = strdup(SLD_MARK_SYMBOL_X); psSymbol->type = MS_SYMBOL_VECTOR; //if (bFilled) // psSymbol->filled = MS_TRUE; psSymbol->points[psSymbol->numpoints].x = 0; psSymbol->points[psSymbol->numpoints].y = 0; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 1; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = -1; psSymbol->points[psSymbol->numpoints].y = -1; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 0; psSymbol->points[psSymbol->numpoints].y = 1; psSymbol->numpoints++; psSymbol->points[psSymbol->numpoints].x = 1; psSymbol->points[psSymbol->numpoints].y = 0; psSymbol->numpoints++; } } return nSymbolId; } extern unsigned char PNGsig[8]; /************************************************************************/ /* msSLDGetGraphicSymbol */ /* */ /* Create a symbol entry for an inmap pixmap symbol. Returns */ /* the symbol id. */ /************************************************************************/ int msSLDGetGraphicSymbol(mapObj *map, char *pszFileName) { FILE *fp; char bytes[8]; gdImagePtr img = NULL; int nSymbolId = 0; symbolObj *psSymbol = NULL; if (map && pszFileName) { //check if a symbol of a fp = fopen(pszFileName, "rb"); if (fp) { fread(bytes,8,1,fp); rewind(fp); if (memcmp(bytes,"GIF8",4)==0) { #ifdef USE_GD_GIF img = gdImageCreateFromGif(fp); #endif } else if (memcmp(bytes,PNGsig,8)==0) { #ifdef USE_GD_PNG img = gdImageCreateFromPng(fp); #endif } fclose(fp); if (img) { psSymbol = &map->symbolset.symbol[map->symbolset.numsymbols]; nSymbolId = map->symbolset.numsymbols; map->symbolset.numsymbols++; initSymbol(psSymbol); psSymbol->inmapfile = MS_TRUE; psSymbol->sizex = 1; psSymbol->sizey = 1; psSymbol->type = MS_SYMBOL_PIXMAP; psSymbol->img = img; } } } return nSymbolId; } /************************************************************************/ /* msSLDParsePointSymbolizer */ /* */ /* Parse point symbolizer. */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /************************************************************************/ void msSLDParsePointSymbolizer(CPLXMLNode *psRoot, layerObj *psLayer, int bNewClass) { int nClassId = 0; int iStyle = 0; if (psRoot && psLayer) { if (bNewClass || psLayer->numclasses <= 0) { initClass(&(psLayer->class[psLayer->numclasses])); nClassId = psLayer->numclasses; psLayer->numclasses++; } else nClassId = psLayer->numclasses-1; iStyle = psLayer->class[nClassId].numstyles; initStyle(&(psLayer->class[nClassId].styles[iStyle])); psLayer->class[nClassId].numstyles++; msSLDParseGraphicFillOrStroke(psRoot, NULL, &psLayer->class[nClassId].styles[iStyle], psLayer->map, 1); } } /************************************************************************/ /* msSLDParseExternalGraphic */ /* */ /* Parse extrenal graphic node : download the symbol referneced */ /* by the URL and create a PIXMAP inmap symbol. Only GIF and */ /* PNG are supported. */ /************************************************************************/ void msSLDParseExternalGraphic(CPLXMLNode *psExternalGraphic, styleObj *psStyle, mapObj *map) { //needed for libcurl function msHTTPGetFile in maphttp.c #if defined(USE_WMS_LYR) || defined(USE_WFS_LYR) char *pszFormat = NULL; CPLXMLNode *psURL=NULL, *psFormat=NULL; char *pszURL=NULL, *pszTmpSymbolName=NULL; int status; if (psExternalGraphic && psStyle && map) { psFormat = CPLGetXMLNode(psExternalGraphic, "Format"); if (psFormat && psFormat->psChild && psFormat->psChild->pszValue) pszFormat = psFormat->psChild->pszValue; //supports GIF and PNG if (pszFormat && (strcasecmp(pszFormat, "GIF") == 0 || strcasecmp(pszFormat, "PNG") == 0)) { psURL = CPLGetXMLNode(psExternalGraphic, "OnlineResource"); if (psURL && psURL->psChild && psURL->psChild->pszValue) { pszURL = psURL->psChild->pszValue; if (strcasecmp(pszFormat, "GIF") == 0) pszTmpSymbolName = msTmpFile(map->web.imagepath, "gif"); else pszTmpSymbolName = msTmpFile(map->web.imagepath, "png"); if (msHTTPGetFile(pszURL, pszTmpSymbolName, &status,-1, 0, 0) == MS_SUCCESS) { psStyle->symbol = msSLDGetGraphicSymbol(map, pszTmpSymbolName); if (psStyle->symbol > 0 && psStyle->symbol < map->symbolset.numsymbols) psStyle->symbolname = strdup(map->symbolset.symbol[psStyle->symbol].name); //set the color parameter if not set. Does not make sense //for pixmap but mapserver needs it. if (psStyle->color.red == -1 || psStyle->color.green || psStyle->color.blue) { psStyle->color.red = 0; psStyle->color.green = 0; psStyle->color.blue = 0; } } } } } #endif } /************************************************************************/ /* msSLDParseTextSymbolizer */ /* */ /* Parse text symbolizer. */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* Four types of CssParameter are allowed, font-family, font-style,*/ /* fontweight,and font-size. */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* The coordinates are given as two floating-point numbers in */ /* the AnchorPointX and AnchorPointY elements each with values */ /* between 0.0 and 1.0 inclusive. The bounding box of the label */ /* to be rendered is considered to be in a coorindate space */ /* from 0.0 (lowerleft corner) to 1.0 (upper-right corner), and */ /* the anchor position is specified as a point in this */ /* space. The default point is X=0, Y=0.5, which is at the */ /* middle height of the lefthand side of the label. */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /************************************************************************/ void msSLDParseTextSymbolizer(CPLXMLNode *psRoot, layerObj *psLayer, int bOtherSymboliser) { int nStyleId=0, nClassId=0; if (psRoot && psLayer) { if (!bOtherSymboliser) { initClass(&(psLayer->class[psLayer->numclasses])); nClassId = psLayer->numclasses; psLayer->numclasses++; initStyle(&(psLayer->class[nClassId].styles[0])); psLayer->class[nClassId].numstyles = 1; nStyleId = 0; } else { nClassId = psLayer->numclasses - 1; if (nClassId >= 0)//should always be true nStyleId = psLayer->class[nClassId].numstyles -1; } if (nStyleId >= 0 && nClassId >= 0) //should always be true msSLDParseTextParams(psRoot, psLayer, &psLayer->class[nClassId]); } } /************************************************************************/ /* msSLDParseRasterSymbolizer */ /* */ /* Supports the ColorMap parameter in a Raster Symbolizer. In */ /* the ColorMap, only color and quantity are used here. */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /************************************************************************/ void msSLDParseRasterSymbolizer(CPLXMLNode *psRoot, layerObj *psLayer) { CPLXMLNode *psColorMap = NULL, *psColorEntry = NULL; char *pszColor=NULL, *pszQuantity=NULL; char *pszPreviousColor=NULL, *pszPreviousQuality=NULL; colorObj sColor; char szExpression[100]; int nClassId = 0; if (!psRoot || !psLayer) return; psColorMap = CPLGetXMLNode(psRoot, "ColorMap"); if (psColorMap) { psColorEntry = CPLGetXMLNode(psColorMap, "ColorMapEntry"); while (psColorEntry && psColorEntry->pszValue && strcasecmp(psColorEntry->pszValue, "ColorMapEntry") == 0) { pszColor = (char *)CPLGetXMLValue(psColorEntry, "color", NULL); pszQuantity = (char *)CPLGetXMLValue(psColorEntry, "quantity", NULL); if (pszColor && pszQuantity) { if (pszPreviousColor && pszPreviousQuality) { if (strlen(pszPreviousColor) == 7 && pszPreviousColor[0] == '#' && strlen(pszColor) == 7 && pszColor[0] == '#') { sColor.red = hex2int(pszPreviousColor+1); sColor.green= hex2int(pszPreviousColor+3); sColor.blue = hex2int(pszPreviousColor+5); //?? Test if pszPreviousQuality < pszQuantity sprintf(szExpression, "([pixel] >= %d AND [pixel] < %d)", atoi(pszPreviousQuality), atoi(pszQuantity)); if (psLayer->numclasses < MS_MAXCLASSES) { initClass(&(psLayer->class[psLayer->numclasses])); psLayer->numclasses++; nClassId = psLayer->numclasses-1; initStyle(&(psLayer->class[nClassId].styles[0])); psLayer->class[nClassId].numstyles = 1; psLayer->class[nClassId].styles[0].color.red = sColor.red; psLayer->class[nClassId].styles[0].color.green = sColor.green; psLayer->class[nClassId].styles[0].color.blue = sColor.blue; if (psLayer->classitem && strcasecmp(psLayer->classitem, "[pixel]") != 0) free(psLayer->classitem); psLayer->classitem = strdup("[pixel]"); loadExpressionString(&psLayer->class[nClassId].expression, szExpression); } } else { msSetError(MS_WMSERR, "Invalid ColorMap Entry.", "msSLDParseRasterSymbolizer()"); } } pszPreviousColor = pszColor; pszPreviousQuality = pszQuantity; } psColorEntry = psColorEntry->psNext; } //do the last Color Map Entry if (pszColor && pszQuantity) { if (strlen(pszColor) == 7 && pszColor[0] == '#') { sColor.red = hex2int(pszColor+1); sColor.green= hex2int(pszColor+3); sColor.blue = hex2int(pszColor+5); sprintf(szExpression, "([pixel] = %d)", atoi(pszQuantity)); if (psLayer->numclasses < MS_MAXCLASSES) { initClass(&(psLayer->class[psLayer->numclasses])); psLayer->numclasses++; nClassId = psLayer->numclasses-1; initStyle(&(psLayer->class[nClassId].styles[0])); psLayer->class[nClassId].numstyles = 1; psLayer->class[nClassId].styles[0].color.red = sColor.red; psLayer->class[nClassId].styles[0].color.green = sColor.green; psLayer->class[nClassId].styles[0].color.blue = sColor.blue; if (psLayer->classitem && strcasecmp(psLayer->classitem, "[pixel]") != 0) free(psLayer->classitem); psLayer->classitem = strdup("[pixel]"); loadExpressionString(&psLayer->class[nClassId].expression, szExpression); } } } } } /************************************************************************/ /* msSLDParseTextParams */ /* */ /* Parse text paramaters like font, placement and color. */ /************************************************************************/ void msSLDParseTextParams(CPLXMLNode *psRoot, layerObj *psLayer, classObj *psClass) { char szFontName[100]; int nFontSize = 10; int bFontSet = 0; CPLXMLNode *psLabel=NULL, *psFont=NULL; CPLXMLNode *psCssParam = NULL; char *pszName=NULL, *pszFontFamily=NULL, *pszFontStyle=NULL; char *pszFontWeight=NULL; CPLXMLNode *psLabelPlacement=NULL, *psPointPlacement=NULL, *psLinePlacement=NULL; CPLXMLNode *psFill = NULL; int nLength = 0; char *pszColor = NULL; szFontName[0]='\0'; if (psRoot && psClass && psLayer) { //label //support only literal expression instead of propertyname psLabel = CPLGetXMLNode(psRoot, "Label"); if (psLabel ) { if (psLabel->psChild && psLabel->psChild->pszValue) //psPropertyName = CPLGetXMLNode(psLabel, "PropertyName"); //if (psPropertyName && psPropertyName->psChild && //psPropertyName->psChild->pszValue) { if (psLayer->labelitem) free (psLayer->labelitem); psLayer->labelitem = strdup(psLabel->psChild->pszValue); //strdup(psPropertyName->psChild->pszValue); //font psFont = CPLGetXMLNode(psRoot, "Font"); if (psFont) { psCssParam = CPLGetXMLNode(psFont, "CssParameter"); while (psCssParam && psCssParam->pszValue && strcasecmp(psCssParam->pszValue, "CssParameter") == 0) { pszName = (char*)CPLGetXMLValue(psCssParam, "name", NULL); if (pszName) { if (strcasecmp(pszName, "font-family") == 0) { if(psCssParam->psChild && psCssParam->psChild->psNext && psCssParam->psChild->psNext->pszValue) pszFontFamily = psCssParam->psChild->psNext->pszValue; } //normal, italic, oblique else if (strcasecmp(pszName, "font-style") == 0) { if(psCssParam->psChild && psCssParam->psChild->psNext && psCssParam->psChild->psNext->pszValue) pszFontStyle = psCssParam->psChild->psNext->pszValue; } //normal or bold else if (strcasecmp(pszName, "font-weight") == 0) { if(psCssParam->psChild && psCssParam->psChild->psNext && psCssParam->psChild->psNext->pszValue) pszFontWeight = psCssParam->psChild->psNext->pszValue; } //default is 10 pix else if (strcasecmp(pszName, "font-size") == 0) { if(psCssParam->psChild && psCssParam->psChild->psNext && psCssParam->psChild->psNext->pszValue) nFontSize = atoi(psCssParam->psChild->psNext->pszValue); if (nFontSize <=0) nFontSize = 10; } } psCssParam = psCssParam->psNext; } } /* -------------------------------------------------------------------- */ /* build the font name using the font font-family, font-style */ /* and font-weight. The name building uses a - between these */ /* parameters and the resulting name is compared to the list of */ /* available fonts. If the name exists, it will be used else we */ /* go to the bitmap fonts. */ /* -------------------------------------------------------------------- */ if (pszFontFamily) { sprintf(szFontName, "%s", pszFontFamily); if (pszFontWeight) { strcat(szFontName, "-"); strcat(szFontName, pszFontWeight); } if (pszFontStyle) { strcat(szFontName, "-"); strcat(szFontName, pszFontStyle); } if ((msLookupHashTable(psLayer->map->fontset.fonts, szFontName) !=NULL)) { bFontSet = 1; psClass->label.font = strdup(szFontName); psClass->label.type = MS_TRUETYPE; psClass->label.size = nFontSize; } } if (!bFontSet) { psClass->label.type = MS_BITMAP; psClass->label.size = MS_MEDIUM; } /* -------------------------------------------------------------------- */ /* parse the label placement. */ /* -------------------------------------------------------------------- */ psLabelPlacement = CPLGetXMLNode(psRoot, "LabelPlacement"); if (psLabelPlacement) { psPointPlacement = CPLGetXMLNode(psLabelPlacement, "PointPlacement"); psLinePlacement = CPLGetXMLNode(psLabelPlacement, "LinePlacement"); if (psPointPlacement) ParseTextPointPlacement(psPointPlacement, psClass); if (psLinePlacement) ParseTextLinePlacement(psPointPlacement, psClass); } /* -------------------------------------------------------------------- */ /* Parse the color */ /* -------------------------------------------------------------------- */ psFill = CPLGetXMLNode(psRoot, "Fill"); if (psFill) { psCssParam = CPLGetXMLNode(psFill, "CssParameter"); while (psCssParam && psCssParam->pszValue && strcasecmp(psCssParam->pszValue, "CssParameter") == 0) { pszName = (char*)CPLGetXMLValue(psCssParam, "name", NULL); if (pszName) { if (strcasecmp(pszName, "fill") == 0) { if(psCssParam->psChild && psCssParam->psChild->psNext && psCssParam->psChild->psNext->pszValue) pszColor = psCssParam->psChild->psNext->pszValue; if (pszColor) { nLength = strlen(pszColor); //expecting hexadecimal ex : #aaaaff if (nLength == 7 && pszColor[0] == '#') { psClass->label.color.red = hex2int(pszColor+1); psClass->label.color.green = hex2int(pszColor+3); psClass->label.color.blue = hex2int(pszColor+5); } } } } psCssParam = psCssParam->psNext; } } }//labelitem } //TODO : support Halo parameter => shadow } } /************************************************************************/ /* ParseTextPointPlacement */ /* */ /* point plavament node ifor the text symbolizer. */ /************************************************************************/ void ParseTextPointPlacement(CPLXMLNode *psRoot, classObj *psClass) { CPLXMLNode *psAnchor, *psAnchorX, *psAnchorY; double dfAnchorX=0, dfAnchorY=0; CPLXMLNode *psDisplacement, *psDisplacementX, *psDisplacementY; CPLXMLNode *psRotation; if (psRoot && psClass) { //init the label with the default position psClass->label.position = MS_CL; /* -------------------------------------------------------------------- */ /* parse anchor point. see function msSLDParseTextSymbolizer */ /* for documentation. */ /* -------------------------------------------------------------------- */ psAnchor = CPLGetXMLNode(psRoot, "AnchorPoint"); if (psAnchor) { psAnchorX = CPLGetXMLNode(psAnchor, "AnchorPointX"); psAnchorY = CPLGetXMLNode(psAnchor, "AnchorPointY"); //psCssParam->psChild->psNext->pszValue) if (psAnchorX && psAnchorX->psChild && psAnchorX->psChild->pszValue && psAnchorY && psAnchorY->psChild && psAnchorY->psChild->pszValue) { dfAnchorX = atof(psAnchorX->psChild->pszValue); dfAnchorY = atof(psAnchorY->psChild->pszValue); if ((dfAnchorX == 0 || dfAnchorX == 0.5 || dfAnchorX == 1) && (dfAnchorY == 0 || dfAnchorY == 0.5 || dfAnchorY == 1)) { if (dfAnchorX == 0 && dfAnchorY == 0) psClass->label.position = MS_LL; if (dfAnchorX == 0 && dfAnchorY == 0.5) psClass->label.position = MS_CL; if (dfAnchorX == 0 && dfAnchorY == 1) psClass->label.position = MS_UL; if (dfAnchorX == 0.5 && dfAnchorY == 0) psClass->label.position = MS_LC; if (dfAnchorX == 0.5 && dfAnchorY == 0.5) psClass->label.position = MS_CC; if (dfAnchorX == 0.5 && dfAnchorY == 1) psClass->label.position = MS_UC; if (dfAnchorX == 1 && dfAnchorY == 0) psClass->label.position = MS_LR; if (dfAnchorX == 1 && dfAnchorY == 0.5) psClass->label.position = MS_CR; if (dfAnchorX == 1 && dfAnchorY == 1) psClass->label.position = MS_UR; } } } /* -------------------------------------------------------------------- */ /* Parse displacement */ /* -------------------------------------------------------------------- */ psDisplacement = CPLGetXMLNode(psRoot, "Displacement"); if (psDisplacement) { psDisplacementX = CPLGetXMLNode(psDisplacement, "DisplacementX"); psDisplacementY = CPLGetXMLNode(psDisplacement, "DisplacementY"); //psCssParam->psChild->psNext->pszValue) if (psDisplacementX && psDisplacementX->psChild && psDisplacementX->psChild->pszValue && psDisplacementY && psDisplacementY->psChild && psDisplacementY->psChild->pszValue) { psClass->label.offsetx = atoi(psDisplacementX->psChild->pszValue); psClass->label.offsety = atoi(psDisplacementY->psChild->pszValue); } } /* -------------------------------------------------------------------- */ /* parse rotation. */ /* -------------------------------------------------------------------- */ psRotation = CPLGetXMLNode(psRoot, "Rotation"); if (psRotation && psRotation->psChild && psRotation->psChild->pszValue) psClass->label.angle = atof(psRotation->psChild->pszValue); } } /************************************************************************/ /* ParseTextLinePlacement */ /* */ /* Lineplacement node fro the text symbolizer. */ /************************************************************************/ void ParseTextLinePlacement(CPLXMLNode *psRoot, classObj *psClass) { CPLXMLNode *psOffset = NULL; if (psRoot && psClass) { psOffset = CPLGetXMLNode(psRoot, "PerpendicularOffset"); if (psOffset && psOffset->psChild && psOffset->psChild->pszValue) { psClass->label.offsetx = atoi(psOffset->psChild->pszValue); psClass->label.offsety = atoi(psOffset->psChild->pszValue); } } } /************************************************************************/ /* void msSLDSetColorObject(char *psHexColor, colorObj */ /* *psColor) */ /* */ /* Utility function to exctract rgb values from an hexadecimal */ /* color string (format is : #aaff08) and set it in the color */ /* object. */ /************************************************************************/ void msSLDSetColorObject(char *psHexColor, colorObj *psColor) { if (psHexColor && psColor && strlen(psHexColor)== 7 && psHexColor[0] == '#') { psColor->red = hex2int(psHexColor+1); psColor->green = hex2int(psHexColor+3); psColor->blue= hex2int(psHexColor+5); } } #endif /* -------------------------------------------------------------------- */ /* client sld support functions */ /* -------------------------------------------------------------------- */ char *msSLDGenerateSLD(mapObj *map, int iLayer) { #ifdef USE_OGR char szTmp[100]; int i = 0; char *pszTmp = NULL; char *pszSLD = NULL; if (map) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); if (iLayer < 0 || iLayer > map->numlayers -1) { for (i=0; inumlayers; i++) { pszTmp = msSLDGenerateSLDLayer(&map->layers[i]); if (pszTmp) { pszSLD= strcatalloc(pszSLD, pszTmp); free(pszTmp); } } } else { pszTmp = msSLDGenerateSLDLayer(&map->layers[iLayer]); if (pszTmp) { pszSLD = strcatalloc(pszSLD, pszTmp); free(pszTmp); } } sprintf(szTmp, "%s", "\n"); pszSLD = strcatalloc(pszSLD, szTmp); } return pszSLD; #else /* ------------------------------------------------------------------ * OGR Support not included... * ------------------------------------------------------------------ */ msSetError(MS_MISCERR, "OGR support is not available.", "msSLDGenerateSLD()"); return NULL; #endif /* USE_OGR */ } /************************************************************************/ /* msSLDGetGraphicSLD */ /* */ /* Get an SLD dor a sytle containg a symbol (Mark or external). */ /************************************************************************/ char *msSLDGetGraphicSLD(styleObj *psStyle, layerObj *psLayer) { char *pszSLD = NULL; int nSymbol = -1; symbolObj *psSymbol = NULL; char szTmp[100]; char *pszURL = NULL; char szFormat[4]; int i = 0, nLength = 0; int bFillColor = 0, bColorAvailable=0; int bGenerateDefaultSymbol = 0; char *pszSymbolName= NULL; if (psStyle && psLayer && psLayer->map) { nSymbol = -1; if (psStyle->symbol > 0) nSymbol = psStyle->symbol; else if (psStyle->symbolname) nSymbol = msGetSymbolIndex(&psLayer->map->symbolset, psStyle->symbolname); bGenerateDefaultSymbol = 0; if (nSymbol <=0 || nSymbol >= psLayer->map->symbolset.numsymbols) bGenerateDefaultSymbol = 1; if (nSymbol > 0 && nSymbol < psLayer->map->symbolset.numsymbols) { psSymbol = &psLayer->map->symbolset.symbol[nSymbol]; if (psSymbol->type == MS_SYMBOL_VECTOR || psSymbol->type == MS_SYMBOL_ELLIPSE) { //Mark symbol if (psSymbol->name) { if (strcasecmp(psSymbol->name, "square") == 0 || strcasecmp(psSymbol->name, "circle") == 0 || strcasecmp(psSymbol->name, "triangle") == 0 || strcasecmp(psSymbol->name, "star") == 0 || strcasecmp(psSymbol->name, "cross") == 0 || strcasecmp(psSymbol->name, "x") == 0) pszSymbolName = strdup(psSymbol->name); else if (strncasecmp(psSymbol->name, "sld_mark_symbol_square", 22) == 0) pszSymbolName = strdup("square"); else if (strncasecmp(psSymbol->name, "sld_mark_symbol_triangle", 24) == 0) pszSymbolName = strdup("triangle"); else if (strncasecmp(psSymbol->name, "sld_mark_symbol_circle", 22) == 0) pszSymbolName = strdup("circle"); else if (strncasecmp(psSymbol->name, "sld_mark_symbol_star", 20) == 0) pszSymbolName = strdup("star"); else if (strncasecmp(psSymbol->name, "sld_mark_symbol_cross", 21) == 0) pszSymbolName = strdup("cross"); else if (strncasecmp(psSymbol->name, "sld_mark_symbol_x", 17) == 0) pszSymbolName = strdup("X"); if (pszSymbolName) { colorObj sTmpColor; sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); if (psStyle->size > 0) sprintf(szTmp, "%d\n", psStyle->size); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", pszSymbolName); pszSLD = strcatalloc(pszSLD, szTmp); if (psStyle->color.red != -1 && psStyle->color.green != -1 && psStyle->color.blue != -1) { sTmpColor.red = psStyle->color.red; sTmpColor.green = psStyle->color.green; sTmpColor.blue = psStyle->color.blue; bFillColor =1; } else if (psStyle->outlinecolor.red != -1 && psStyle->outlinecolor.green != -1 && psStyle->outlinecolor.blue != -1) { sTmpColor.red = psStyle->outlinecolor.red; sTmpColor.green = psStyle->outlinecolor.green; sTmpColor.blue = psStyle->outlinecolor.blue; bFillColor = 0; } else { sTmpColor.red = 128; sTmpColor.green = 128; sTmpColor.blue = 128; bFillColor =1; } if (psLayer->type == MS_LAYER_POINT) { if (psSymbol->filled) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "#%02x%02x%02x\n", sTmpColor.red, sTmpColor.green, sTmpColor.blue); } else { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "#%02x%02x%02x\n", sTmpColor.red, sTmpColor.green, sTmpColor.blue); } } else { if (bFillColor) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "#%02x%02x%02x\n", sTmpColor.red, sTmpColor.green, sTmpColor.blue); } else { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "#%02x%02x%02x\n", sTmpColor.red, sTmpColor.green, sTmpColor.blue); } } pszSLD = strcatalloc(pszSLD, szTmp); if ((psLayer->type == MS_LAYER_POINT && psSymbol->filled) || bFillColor) sprintf(szTmp, "%s\n", ""); else sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n%s\n", "", ""); pszSLD = strcatalloc(pszSLD, szTmp); if (pszSymbolName) free(pszSymbolName); } } else bGenerateDefaultSymbol =1; } else if (psSymbol->type == MS_SYMBOL_PIXMAP) { if (psSymbol->name) { pszURL = msLookupHashTable(psLayer->metadata, "WMS_SLD_SYMBOL_URL"); if (!pszURL) pszURL = msLookupHashTable(psLayer->map->web.metadata, "WMS_SLD_SYMBOL_URL"); if (pszURL) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); if (psStyle->size > 0) sprintf(szTmp, "%d\n", psStyle->size); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s%s\n", pszURL,psSymbol->imagepath); pszSLD = strcatalloc(pszSLD, szTmp); //TODO : extract format from symbol szFormat[0] = '\0'; nLength = strlen(psSymbol->imagepath); if (nLength > 3) { for (i=0; i<=2; i++) szFormat[2-i] = psSymbol->imagepath[nLength-1-i]; szFormat[3] = '\0'; } if (strlen(szFormat) > 0 && ((strcasecmp (szFormat, "GIF") == 0) || (strcasecmp (szFormat, "PNG") == 0))) { sprintf(szTmp, "%s\n", szFormat); } else sprintf(szTmp, "%s\n", "GIF"); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n%s\n", "" , ""); pszSLD = strcatalloc(pszSLD, szTmp); } } } } if (bGenerateDefaultSymbol) //genrate a default square symbol { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); if (psStyle->size > 0) sprintf(szTmp, "%d\n", psStyle->size); else sprintf(szTmp, "%d\n", 1); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", "square"); pszSLD = strcatalloc(pszSLD, szTmp); bColorAvailable = 0; if (psStyle->color.red != -1 && psStyle->color.green != -1 && psStyle->color.blue != -1) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "#%02x%02x%02x\n", psStyle->color.red, psStyle->color.green, psStyle->color.blue); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); bColorAvailable = 1; } if (psStyle->outlinecolor.red != -1 && psStyle->outlinecolor.green != -1 && psStyle->outlinecolor.blue != -1) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "#%02x%02x%02x\n", psStyle->outlinecolor.red, psStyle->outlinecolor.green, psStyle->outlinecolor.blue); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); bColorAvailable = 1; } if (!bColorAvailable) { //default color sprintf(szTmp, "%s\n", "#808080"); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); } sprintf(szTmp, "%s\n%s\n", "", ""); pszSLD = strcatalloc(pszSLD, szTmp); } } return pszSLD; } /************************************************************************/ /* msSLDGenerateLineSLD */ /* */ /* Generate SLD for a Line layer. */ /************************************************************************/ char *msSLDGenerateLineSLD(styleObj *psStyle, layerObj *psLayer) { char *pszSLD = NULL; char szTmp[100]; char szHexColor[7]; int nSymbol = -1; symbolObj *psSymbol = NULL; int i = 0; int nSize = 1; char *pszDashArray = NULL; char *pszGraphicSLD = NULL; sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szHexColor,"%02x%02x%02x",psStyle->color.red, psStyle->color.green,psStyle->color.blue); sprintf(szTmp, "#%s\n", szHexColor); pszSLD = strcatalloc(pszSLD, szTmp); nSymbol = -1; if (psStyle->symbol > 0) nSymbol = psStyle->symbol; else if (psStyle->symbolname) nSymbol = msGetSymbolIndex(&psLayer->map->symbolset, psStyle->symbolname); //if no symbol or symbol 0 is used, size is set to 1 //which is the way mapserver works if (nSymbol <=0) nSize = 1; else nSize = psStyle->size; sprintf(szTmp, "%d\n", nSize); pszSLD = strcatalloc(pszSLD, szTmp); /* -------------------------------------------------------------------- */ /* dash array */ /* -------------------------------------------------------------------- */ if (nSymbol > 0 && nSymbol < psLayer->map->symbolset.numsymbols) { psSymbol = &psLayer->map->symbolset.symbol[nSymbol]; if (psSymbol->stylelength > 0) { for (i=0; istylelength; i++) { sprintf(szTmp, "%d ", psSymbol->style[i]); pszDashArray = strcatalloc(pszDashArray, szTmp); } sprintf(szTmp, "%s\n", pszDashArray); pszSLD = strcatalloc(pszSLD, szTmp); } } //TODO : does not work (color is not picked) //pszGraphicSLD = msSLDGetGraphicSLD(psStyle, psLayer); if (pszGraphicSLD) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); pszSLD = strcatalloc(pszSLD, pszGraphicSLD); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); free(pszGraphicSLD); pszGraphicSLD = NULL; } sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); return pszSLD; } /************************************************************************/ /* msSLDGeneratePolygonSLD */ /* */ /* Generate SLD for a Polygon layer. */ /************************************************************************/ char *msSLDGeneratePolygonSLD(styleObj *psStyle, layerObj *psLayer) { char szTmp[100]; char *pszSLD = NULL; char szHexColor[7]; char *pszGraphicSLD = NULL; sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); //fill if (psStyle->color.red != -1 && psStyle->color.green != -1 && psStyle->color.blue != -1) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szHexColor,"%02x%02x%02x",psStyle->color.red, psStyle->color.green,psStyle->color.blue); sprintf(szTmp, "#%s\n", szHexColor); pszSLD = strcatalloc(pszSLD, szTmp); pszGraphicSLD = msSLDGetGraphicSLD(psStyle, psLayer); if (pszGraphicSLD) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); pszSLD = strcatalloc(pszSLD, pszGraphicSLD); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); free(pszGraphicSLD); pszGraphicSLD = NULL; } sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); } //stroke if (psStyle->outlinecolor.red != -1 && psStyle->outlinecolor.green != -1 && psStyle->outlinecolor.blue != -1) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szHexColor,"%02x%02x%02x",psStyle->outlinecolor.red, psStyle->outlinecolor.green, psStyle->outlinecolor.blue); sprintf(szTmp, "#%s\n", szHexColor); pszSLD = strcatalloc(pszSLD, szTmp); //If there is a symbol to be used for sroke, the color in the //style sholud be set to -1. Else It won't apply here. if (psStyle->color.red == -1 && psStyle->color.green == -1 && psStyle->color.blue == -1) { pszGraphicSLD = msSLDGetGraphicSLD(psStyle, psLayer); if (pszGraphicSLD) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); pszSLD = strcatalloc(pszSLD, pszGraphicSLD); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); free(pszGraphicSLD); pszGraphicSLD = NULL; } } sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); } sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); return pszSLD; } /************************************************************************/ /* msSLDGeneratePointSLD */ /* */ /* Generate SLD for a Point layer. */ /************************************************************************/ char *msSLDGeneratePointSLD(styleObj *psStyle, layerObj *psLayer) { char *pszSLD = NULL; char *pszGraphicSLD = NULL; char szTmp[100]; sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); pszGraphicSLD = msSLDGetGraphicSLD(psStyle, psLayer); if (pszGraphicSLD) { pszSLD = strcatalloc(pszSLD, pszGraphicSLD); free(pszGraphicSLD); } sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); return pszSLD; } /************************************************************************/ /* msSLDGenerateTextSLD */ /* */ /* Generate a TextSymboliser SLD xml based on the class's label */ /* object. */ /************************************************************************/ char *msSLDGenerateTextSLD(classObj *psClass, layerObj *psLayer) { char *pszSLD = NULL; char szTmp[100]; char **aszFontsParts = NULL; int nFontParts = 0; char szHexColor[7]; int nColorRed=-1, nColorGreen=-1, nColorBlue=-1; double dfAnchorX = 0.5, dfAnchorY = 0.5; int i = 0; if (psClass && psLayer && psLayer->labelitem) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "\n", psLayer->labelitem); pszSLD = strcatalloc(pszSLD, szTmp); /* -------------------------------------------------------------------- */ /* only true type fonta are exported. Font name should be */ /* something like arial-bold-italic. There are 3 parts to the */ /* name font-family, font-style (italic, oblique, nomal), */ /* font-weight (bold, normal). These 3 elements are separated */ /* with -. */ /* -------------------------------------------------------------------- */ if (psClass->label.type == MS_TRUETYPE && psClass->label.font) { aszFontsParts = split(psClass->label.font, '-', &nFontParts); if (nFontParts > 0) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); //assuming first one is font-family sprintf(szTmp, "%s\n", aszFontsParts[0]); pszSLD = strcatalloc(pszSLD, szTmp); for (i=1; i%s\n", aszFontsParts[i]); pszSLD = strcatalloc(pszSLD, szTmp); } else if (strcasecmp(aszFontsParts[i], "bold") == 0) { sprintf(szTmp, "%s\n", aszFontsParts[i]); pszSLD = strcatalloc(pszSLD, szTmp); } } //size if (psClass->label.size > 0) { sprintf(szTmp, "%d\n", psClass->label.size); pszSLD = strcatalloc(pszSLD, szTmp); } sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); msFreeCharArray(aszFontsParts, nFontParts); } } //color if (psClass->label.color.red != -1 && psClass->label.color.green != -1 && psClass->label.color.blue != -1) { nColorRed = psClass->label.color.red; nColorGreen = psClass->label.color.green; nColorBlue = psClass->label.color.blue; } else if (psClass->label.outlinecolor.red != -1 && psClass->label.outlinecolor.green != -1 && psClass->label.outlinecolor.blue != -1) { nColorRed = psClass->label.outlinecolor.red; nColorGreen = psClass->label.outlinecolor.green; nColorBlue = psClass->label.outlinecolor.blue; } if (nColorRed >= 0 && nColorGreen >= 0 && nColorBlue >=0) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szHexColor,"%02x%02x%02x",nColorRed, nColorGreen, nColorBlue); sprintf(szTmp, "#%s\n", szHexColor); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); } //label placement sprintf(szTmp, "%s\n%s\n", "", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); if (psClass->label.position == MS_LL) { dfAnchorX =0; dfAnchorY = 0; } else if (psClass->label.position == MS_CL) { dfAnchorX =0; dfAnchorY = 0.5; } else if (psClass->label.position == MS_UL) { dfAnchorX =0; dfAnchorY = 1; } else if (psClass->label.position == MS_LC) { dfAnchorX =0.5; dfAnchorY = 0; } else if (psClass->label.position == MS_CC) { dfAnchorX =0.5; dfAnchorY = 0.5; } else if (psClass->label.position == MS_UC) { dfAnchorX =0.5; dfAnchorY = 1; } else if (psClass->label.position == MS_LR) { dfAnchorX =1; dfAnchorY = 0; } else if (psClass->label.position == MS_CR) { dfAnchorX =1; dfAnchorY = 0.5; } else if (psClass->label.position == MS_UR) { dfAnchorX =1; dfAnchorY = 1; } sprintf(szTmp, "%.1f\n", dfAnchorX); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%.1f\n", dfAnchorY); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); //displacement if (psClass->label.offsetx > 0 || psClass->label.offsety > 0) { sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); if (psClass->label.offsetx > 0) { sprintf(szTmp, "%d\n", psClass->label.offsetx); pszSLD = strcatalloc(pszSLD, szTmp); } if (psClass->label.offsety > 0) { sprintf(szTmp, "%d\n", psClass->label.offsety); pszSLD = strcatalloc(pszSLD, szTmp); } sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); } //rotation if (psClass->label.angle > 0) { sprintf(szTmp, "%.2f\n", psClass->label.angle); pszSLD = strcatalloc(pszSLD, szTmp); } //TODO : support Halo parameter => shadow sprintf(szTmp, "%s\n%s\n", "", ""); pszSLD = strcatalloc(pszSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszSLD = strcatalloc(pszSLD, szTmp); } return pszSLD; } /************************************************************************/ /* msSLDGenerateSLDLayer */ /* */ /* Genrate an SLD XML string based on the layer's classes. */ /************************************************************************/ char *msSLDGenerateSLDLayer(layerObj *psLayer) { #ifdef USE_OGR char szTmp[100]; int i, j; styleObj *psStyle = NULL; char *pszFilter = NULL; char *pszFinalSLD = NULL; char *pszSLD = NULL; char *pszTmp = NULL; if (psLayer && (psLayer->type == MS_LAYER_POINT || psLayer->type == MS_LAYER_LINE || psLayer->type == MS_LAYER_POLYGON || psLayer->type == MS_LAYER_ANNOTATION)) { sprintf(szTmp, "%s\n", ""); pszFinalSLD = strcatalloc(pszFinalSLD, szTmp); pszTmp = msLookupHashTable(psLayer->metadata, "wms_name"); if (pszTmp) sprintf(szTmp, "%s\n", pszTmp); else if (psLayer->name) sprintf(szTmp, "%s\n", psLayer->name); else sprintf(szTmp, "%s\n", "NamedLayer"); pszFinalSLD = strcatalloc(pszFinalSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszFinalSLD = strcatalloc(pszFinalSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszFinalSLD = strcatalloc(pszFinalSLD, szTmp); if (psLayer->numclasses > 0) { for (i=psLayer->numclasses-1; i>=0; i--) { sprintf(szTmp, "%s\n", ""); pszFinalSLD = strcatalloc(pszFinalSLD, szTmp); /* -------------------------------------------------------------------- */ /* get the Filter if there is a class expression. */ /* -------------------------------------------------------------------- */ pszFilter = msSLDGetFilter(&psLayer->class[i]); if (pszFilter) { pszFinalSLD = strcatalloc(pszFinalSLD, pszFilter); free(pszFilter); } /* -------------------------------------------------------------------- */ /* Line symbolizer. */ /* */ /* Right now only generates a stroke element containing css */ /* parameters. */ /* Lines using symbols TODO (specially for dash lines) */ /* -------------------------------------------------------------------- */ if (psLayer->type == MS_LAYER_LINE) { for (j=0; jclass[i].numstyles; j++) { psStyle = &psLayer->class[i].styles[j]; pszSLD = msSLDGenerateLineSLD(psStyle, psLayer); if (pszSLD) { pszFinalSLD = strcatalloc(pszFinalSLD, pszSLD); free(pszSLD); } } } else if (psLayer->type == MS_LAYER_POLYGON) { for (j=0; jclass[i].numstyles; j++) { psStyle = &psLayer->class[i].styles[j]; pszSLD = msSLDGeneratePolygonSLD(psStyle, psLayer); if (pszSLD) { pszFinalSLD = strcatalloc(pszFinalSLD, pszSLD); free(pszSLD); } } } else if (psLayer->type == MS_LAYER_POINT) { for (j=0; jclass[i].numstyles; j++) { psStyle = &psLayer->class[i].styles[j]; pszSLD = msSLDGeneratePointSLD(psStyle, psLayer); if (pszSLD) { pszFinalSLD = strcatalloc(pszFinalSLD, pszSLD); free(pszSLD); } } } else if (psLayer->type == MS_LAYER_ANNOTATION) { for (j=0; jclass[i].numstyles; j++) { psStyle = &psLayer->class[i].styles[j]; pszSLD = msSLDGeneratePointSLD(psStyle, psLayer); if (pszSLD) { pszFinalSLD = strcatalloc(pszFinalSLD, pszSLD); free(pszSLD); } } } //label if it exists pszSLD = msSLDGenerateTextSLD(&psLayer->class[i], psLayer); if (pszSLD) { pszFinalSLD = strcatalloc(pszFinalSLD, pszSLD); free(pszSLD); } sprintf(szTmp, "%s\n", ""); pszFinalSLD = strcatalloc(pszFinalSLD, szTmp); } } sprintf(szTmp, "%s\n", ""); pszFinalSLD = strcatalloc(pszFinalSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszFinalSLD = strcatalloc(pszFinalSLD, szTmp); sprintf(szTmp, "%s\n", ""); pszFinalSLD = strcatalloc(pszFinalSLD, szTmp); } return pszFinalSLD; #else /* ------------------------------------------------------------------ * OGR Support not included... * ------------------------------------------------------------------ */ msSetError(MS_MISCERR, "OGR support is not available.", "msSLDGenerateSLDLayer()"); return NULL; #endif /* USE_OGR */ } #ifdef USE_OGR char *msSLDSimplifyExpression(char *pszExpression) { return NULL; } char *msSLDGetComparisonValue(char *pszExpression) { char *pszValue = NULL; if (!pszExpression) return NULL; if (strstr(pszExpression, "=") || strstr(pszExpression, " eq ")) pszValue = strdup("PropertyIsEqualTo"); else if (strstr(pszExpression, "!=") || strstr(pszExpression, " ne ")) pszValue = strdup("PropertyIsNotEqualTo"); else if (strstr(pszExpression, "<") || strstr(pszExpression, " lt ")) pszValue = strdup("PropertyIsLessThan"); else if (strstr(pszExpression, ">") || strstr(pszExpression, " gt ")) pszValue = strdup("PropertyIsGreaterThan"); else if (strstr(pszExpression, "<=") || strstr(pszExpression, " le ")) pszValue = strdup("PropertyIsLessThanOrEqualTo"); else if (strstr(pszExpression, ">=") || strstr(pszExpression, " ge ")) pszValue = strdup("PropertyIsGreaterThanOrEqualTo"); return pszValue; } char *msSLDGetLogicalOperator(char *pszExpression) { if (!pszExpression) return NULL; //TODO for NOT if(strstr(pszExpression, " AND ") || strstr(pszExpression, "AND(")) return strdup("AND"); if(strstr(pszExpression, " OR ") || strstr(pszExpression, "OR(")) return strdup("AND"); return NULL; } char *msSLDGetRightExpressionOfOperator(char *pszExpression) { char *pszAnd = NULL, *pszOr = NULL; pszAnd = strstr(pszExpression, " AND "); if (!pszAnd) strstr(pszExpression, " and "); if (pszAnd) return strdup(pszAnd+4); else { pszOr = strstr(pszExpression, " OR "); if (!pszOr) strstr(pszExpression, " or "); if (pszOr) return strdup(pszOr+3); } return NULL; } char *msSLDGetLeftExpressionOfOperator(char *pszExpression) { char *pszReturn = NULL; int nLength = 0, i =0, iReturn=0; if (!pszExpression || (nLength = strlen(pszExpression)) <=0) return NULL; pszReturn = (char *)malloc(sizeof(char)*(nLength+1)); pszReturn[0] = '\0'; if (strstr(pszExpression, " AND ") || strstr(pszExpression, " and ")) { for (i=0; i= 1) { pszAttributeName = strdup(aszValues[0]); pszAttributeValue = strdup(aszValues[1]); msFreeCharArray(aszValues, nTokens); } else { nLength = strlen(pszExpression); pszAttributeName = (char *)malloc(sizeof(char)*(nLength+1)); iValue = 0; for (i=0; i, >= .... We get the comparison value as well as the */ /* attribute and the attribut's value and assign it to the node */ /* passed in argument. */ /* - if there is one operator, we assign the operator to the */ /* node and adds the expressions into the left and right nodes. */ /* -------------------------------------------------------------------- */ nOperators = msSLDNumberOfLogicalOperators(pszExpression); if (nOperators == 0) { if (!psNode) psNode = FLTCreateFilterEncodingNode(); pszComparionValue = msSLDGetComparisonValue(pszExpression); pszAttibuteName = msSLDGetAttributeName(pszExpression, pszComparionValue); pszAttibuteValue = msSLDGetAttributeValue(pszExpression, pszComparionValue); if (pszComparionValue && pszAttibuteName && pszAttibuteValue) { psNode->eType = FILTER_NODE_TYPE_COMPARISON; psNode->pszValue = strdup(pszComparionValue); psNode->psLeftNode = FLTCreateFilterEncodingNode(); psNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; psNode->psLeftNode->pszValue = strdup(pszAttibuteName); psNode->psRightNode = FLTCreateFilterEncodingNode(); psNode->psRightNode->eType = FILTER_NODE_TYPE_LITERAL; psNode->psRightNode->pszValue = strdup(pszAttibuteValue); free(pszComparionValue); free(pszAttibuteName); free(pszAttibuteValue); } return psNode; } else if (nOperators == 1) { pszOperator = msSLDGetLogicalOperator(pszExpression); if (pszOperator) { if (!psNode) psNode = FLTCreateFilterEncodingNode(); psNode->eType = FILTER_NODE_TYPE_LOGICAL; psNode->pszValue = strdup(pszOperator); free(pszOperator); pszLeftExpression = msSLDGetLeftExpressionOfOperator(pszExpression); pszRightExpression = msSLDGetRightExpressionOfOperator(pszExpression); if (pszLeftExpression && pszRightExpression) { pszComparionValue = msSLDGetComparisonValue(pszLeftExpression); pszAttibuteName = msSLDGetAttributeName(pszLeftExpression, pszComparionValue); pszAttibuteValue = msSLDGetAttributeValue(pszLeftExpression, pszComparionValue); if (pszComparionValue && pszAttibuteName && pszAttibuteValue) { psNode->psLeftNode = FLTCreateFilterEncodingNode(); psNode->psLeftNode->eType = FILTER_NODE_TYPE_COMPARISON; psNode->psLeftNode->pszValue = strdup(pszComparionValue); psNode->psLeftNode->psLeftNode = FLTCreateFilterEncodingNode(); psNode->psLeftNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; psNode->psLeftNode->psLeftNode->pszValue = strdup(pszAttibuteName); psNode->psLeftNode->psRightNode = FLTCreateFilterEncodingNode(); psNode->psLeftNode->psRightNode->eType = FILTER_NODE_TYPE_LITERAL; psNode->psLeftNode->psRightNode->pszValue = strdup(pszAttibuteValue); free(pszComparionValue); free(pszAttibuteName); free(pszAttibuteValue); } pszComparionValue = msSLDGetComparisonValue(pszRightExpression); pszAttibuteName = msSLDGetAttributeName(pszRightExpression, pszComparionValue); pszAttibuteValue = msSLDGetAttributeValue(pszRightExpression, pszComparionValue); if (pszComparionValue && pszAttibuteName && pszAttibuteValue) { psNode->psRightNode = FLTCreateFilterEncodingNode(); psNode->psRightNode->eType = FILTER_NODE_TYPE_COMPARISON; psNode->psRightNode->pszValue = strdup(pszComparionValue); psNode->psRightNode->psLeftNode = FLTCreateFilterEncodingNode(); psNode->psRightNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME; psNode->psRightNode->psLeftNode->pszValue = strdup(pszAttibuteName); psNode->psRightNode->psRightNode = FLTCreateFilterEncodingNode(); psNode->psRightNode->psRightNode->eType = FILTER_NODE_TYPE_LITERAL; psNode->psRightNode->psRightNode->pszValue = strdup(pszAttibuteValue); free(pszComparionValue); free(pszAttibuteName); free(pszAttibuteValue); } } } return psNode; } else return NULL; /* for (i=0; i 0) { nOpeningBrackets--; apszExpression[iExpression][iIndiceExp++] = pszExpression[i]; } else { //end of an expression pszFinalExpression[iFinal++] = ' '; pszFinalExpression[iFinal] = '\0'; sprintf(szTmp, "exp%d ", iExpression); strcat(pszFinalExpression,szTmp); if (iExpression < 10) iFinal+=5; else iFinal+=6; bInsideExpression = 0; } } } else { if (bInsideExpression) { apszExpression[iExpression][iIndiceExp++] = pszExpression[i]; } else { pszFinalExpression[iFinal++] = pszExpression[i]; } } if (iExpression >=0 && iIndiceExp >0) apszExpression[iExpression][iIndiceExp] = '\0'; if (iFinal > 0) pszFinalExpression[iFinal] = '\0'; } if (msSLDHasMoreThatOneLogicalOperator(pszFinalExpression)) { pszSimplifiedExpression = msSLDSimplifyExpression(pszFinalExpression); free(pszFinalExpression); //increase the size so it can fit the brakets () that will be added pszFinalExpression = (char *)malloc(sizeof(char)*(nLength+3)); if(iExpression > 0) { nLength = strlen(pszSimplifiedExpression); iFinal = 0; for (i=0; i=0 && nIndice < iExpression) { strcat(pszFinalExpression, apszExpression[nIndice]); iFinal+= strlen(apszExpression[nIndice]); } } } else { pszFinalExpression[iFinal++] = pszSimplifiedExpression[i]; } } } else pszFinalExpression = strdup(pszFinalExpression); return BuildExpressionTree(pszFinalExpression, psNode); } pszLogicalOper = msSLDGetLogicalOperator(pszFinalExpression); //TODO : NOT operator if (pszLogicalOper) { if (strcasecmp(pszLogicalOper, "AND") == 0 || strcasecmp(pszLogicalOper, "OR") == 0) { if (!psNode) psNode = FLTCreateFilterEncodingNode(); psNode->eType = FILTER_NODE_TYPE_LOGICAL; if (strcasecmp(pszLogicalOper, "AND") == 0) psNode->pszValue = "AND"; else psNode->pszValue = "OR"; psNode->psLeftNode = FLTCreateFilterEncodingNode(); psNode->psRightNode = FLTCreateFilterEncodingNode(); psLeftExpresion = msSLDGetLogicalOperatorExpression(pszFinalExpression, 0); psRightExpresion = msSLDGetLogicalOperatorExpression(pszFinalExpression, 0); BuildExpressionTree(psNode->psLeftNode, psLeftExpresion); BuildExpressionTree(psNode->psRightNode,psRightExpresion); if (psLeftExpresion) free(psLeftExpresion); if (psRightExpresion) free(psRightExpresion); } } else //means it is a simple expression with comaprison { */ } char *msSLDBuildFilterEncoding(FilterEncodingNode *psNode) { char *pszTmp = NULL; char szTmp[200]; char *pszExpression = NULL; if (!psNode) return NULL; if (psNode->eType == FILTER_NODE_TYPE_COMPARISON && psNode->pszValue && psNode->psLeftNode && psNode->psLeftNode->pszValue && psNode->psRightNode && psNode->psRightNode->pszValue) { sprintf(szTmp," <%s>%s%s", psNode->pszValue, psNode->psLeftNode->pszValue, psNode->psRightNode->pszValue, psNode->pszValue); pszExpression = strdup(szTmp); } else if (psNode->eType == FILTER_NODE_TYPE_LOGICAL && psNode->pszValue && psNode->psLeftNode && psNode->psLeftNode->pszValue && psNode->psRightNode && psNode->psRightNode->pszValue) { sprintf(szTmp, "<%s>", psNode->pszValue); pszExpression = strcatalloc(pszExpression, szTmp); pszTmp = msSLDBuildFilterEncoding(psNode->psLeftNode); if (pszTmp) { pszExpression = strcatalloc(pszExpression, pszTmp); free(pszTmp); } pszTmp = msSLDBuildFilterEncoding(psNode->psRightNode); if (pszTmp) { pszExpression = strcatalloc(pszExpression, pszTmp); free(pszTmp); } sprintf(szTmp, "", psNode->pszValue); pszExpression = strcatalloc(pszExpression, szTmp); } return pszExpression; } char *msSLDParseLogicalExpression(char *pszExpression) { FilterEncodingNode *psNode = NULL; char *pszFLTExpression = NULL; char *pszTmp = NULL; if (!pszExpression || strlen(pszExpression) <=0) return NULL; //psNode = BuildExpressionTree(pszExpression, NULL); psNode = BuildExpressionTree(pszExpression, NULL); if (psNode) { pszFLTExpression = msSLDBuildFilterEncoding(psNode); if (pszFLTExpression) { pszTmp = strcatalloc(pszTmp, ""); pszTmp = strcatalloc(pszTmp, pszFLTExpression); pszTmp = strcatalloc(pszTmp, ""); free(pszFLTExpression); pszFLTExpression = pszTmp; } } return pszFLTExpression; } /************************************************************************/ /* char *msSLDParseExpression(char *pszExpression) */ /* */ /* Return an OGC filter for a mapserver locgical expression. */ /* TODO : move function to mapogcfilter.c */ /************************************************************************/ char *msSLDParseExpression(char *pszExpression) { int nElements = 0; char **aszElements = NULL; char szBuffer[500]; char szFinalAtt[40]; char szFinalValue[40]; char szAttribute[40]; char szValue[40]; int i=0, nLength=0, iAtt=0, iVal=0; int bStartCopy=0, bSinglequote=0, bDoublequote=0; char *pszFilter = NULL; if (!pszExpression) return NULL; nLength = strlen(pszExpression); aszElements = split(pszExpression, ' ', &nElements); szFinalAtt[0] = '\0'; szFinalValue[0] = '\0'; for (i=0; i 0 && i < nElements-1) { sprintf(szAttribute, aszElements[i-1]); sprintf(szValue, aszElements[i+1]); //parse attribute nLength = strlen(szAttribute); if (nLength > 0) { iAtt = 0; for (i=0; i 0) { if (szValue[0] == '\'') bSinglequote = 1; else if (szValue[0] == '\"') bDoublequote = 1; else sprintf(szFinalValue,szValue); iVal = 0; if (bSinglequote || bDoublequote) { for (i=1; i 0 && strlen(szFinalValue) >0) { sprintf(szBuffer, "%s%s", szFinalAtt, szFinalValue); pszFilter = strdup(szBuffer); } } } return pszFilter; } /************************************************************************/ /* msSLDGetFilter */ /* */ /* Get the correspondinf ogc Filter based on the class */ /* expression. TODO : move function to mapogcfilter.c when */ /* finished. */ /************************************************************************/ char *msSLDGetFilter(classObj *psClass) { char *pszFilter = NULL; char szBuffer[500]; if (psClass && psClass->expression.string) { //string expression if (psClass->expression.type == MS_STRING) { if (psClass->layer && psClass->layer->classitem) { sprintf(szBuffer, "%s%s\n", psClass->layer->classitem, psClass->expression.string); pszFilter = strdup(szBuffer); } } else if (psClass->expression.type == MS_EXPRESSION) { pszFilter = msSLDParseLogicalExpression(psClass->expression.string); } else if (psClass->expression.type == MS_REGEX) { if (psClass->layer && psClass->layer->classitem) { sprintf(szBuffer, "%s%s\n", psClass->layer->classitem, psClass->expression.string); pszFilter = strdup(szBuffer); } } } return pszFilter; } #endif