#*************************************************************************** # ms_export.py # -------------------------------------- # Date : Sun Sep 16 12:33:46 AKDT 2007 # Copyright : (C) 2008 by Gary E. Sherman # Email : sherman at mrcc dot com #*************************************************************************** #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU General Public License as published by * #* the Free Software Foundation; either version 2 of the License, or * #* (at your option) any later version. * #* * #***************************************************************************/ # This class exports a QGIS project file to a mapserver .map file. # All the work is done in the writeMapFile method. The msexport binary # presents a Qt based GUI that collects the needed information for this # script. # Matthew Perry contributed major portions of this work. # # CHANGES SHOULD NOT BE MADE TO THE writeMapFile METHOD UNLESS YOU # ARE CHANGING THE QgsMapserverExport CLASS AND YOU KNOW WHAT YOU ARE # DOING import sys import os from string import * from xml.dom import minidom, Node # symbol map qgisSymbols = {'hard:circle' : 'CIRCLE', 'hard:triangle' : 'TRIANGLE'} class Qgis2Map: def __init__(self, projectFile, mapFile): self.project = projectFile self.mapFile = mapFile # create the DOM self.qgs = minidom.parse(projectFile) # init the other members that are not set by the constructor self.units = '' self.imageType = '' self.mapName = '' self.width = '' self.height = '' self.minimumScale = '' self.maximumScale = '' self.template = '' self.header = '' self.footer = '' self.symbolQueue = {} # Set the options collected from the GUI def setOptions(self, units, image, mapname, width, height, template, header, footer): self.units = units self.imageType = str(image) self.mapName = mapname self.width = width self.height = height #self.minimumScale = minscale #self.maximumScale = maxscale self.template = template self.header = header self.footer = footer print units, image, mapname, width, height, template, header, footer ## All real work happens here by calling methods to write the ## various sections of the map file def writeMapFile(self): # open the output file print "creating the map file" self.outFile = open(self.mapFile, 'w') # write the general map and web settings print " --- python : map section " self.writeMapSection() logmsg = "Wrote map section\n" print " --- python : map section done" # write the projection section print " --- python : proj section " self.writeProjectionSection() logmsg += "Wrote projection section\n" print " --- python : proj section done" # write the output format section print " --- python : outputformat section " self.writeOutputFormat() logmsg += "Wrote output format section\n" print " --- python : outputformat section done" # write the legend section print " --- python : legend section" self.writeLegendSection() logmsg += "Wrote legend section\n" print " --- python : legend section done" # write the WEB section print " --- python : web section " self.writeWebSection() logmsg += "Wrote web section\n" print " --- python : web section done" # write the LAYER sections print " --- python : layer section " self.writeMapLayers() logmsg += "Wrote map layers\n" print " --- python : layer section done" # write the symbol defs section # must happen after layers so we can build a symbol queue print " --- python : symbol section " self.writeSymbolSection() logmsg += "Wrote symbol section\n" print " --- python : symbol section done" # END and close the map file self.outFile.write("END") self.outFile.close() logmsg += "Map file completed for " + self.project + "\n" logmsg += "Map file saved as " + self.mapFile + "\n" return logmsg # Write the general parts of the map section def writeMapSection(self): self.outFile.write("# Map file created from QGIS project file " + self.project + "\n") self.outFile.write("# Edit this file to customize for your map interface\n") self.outFile.write("# (Created with PyQgis MapServer Export plugin)\n") self.outFile.write("MAP\n") self.outFile.write(" NAME " + self.mapName + "\n") self.outFile.write(" # Map image size\n") self.outFile.write(" SIZE " + self.width + " " + self.height + "\n") self.outFile.write(" UNITS %s\n" % (self.units)) self.outFile.write("\n") # extents xmin = self.qgs.getElementsByTagName("xmin") self.outFile.write(" EXTENT ") self.outFile.write(xmin[0].childNodes[0].nodeValue.encode('utf-8')) self.outFile.write(" ") ymin = self.qgs.getElementsByTagName("ymin") self.outFile.write(ymin[0].childNodes[0].nodeValue.encode('utf-8')) self.outFile.write(" ") xmax = self.qgs.getElementsByTagName("xmax") self.outFile.write(xmax[0].childNodes[0].nodeValue.encode('utf-8')) self.outFile.write(" ") ymax = self.qgs.getElementsByTagName("ymax") self.outFile.write(ymax[0].childNodes[0].nodeValue.encode('utf-8')) self.outFile.write("\n") # Write the OUTPUTFORMAT section def writeOutputFormat(self): self.outFile.write(" # Background color for the map canvas -- change as desired\n") self.outFile.write(" IMAGECOLOR 192 192 192\n") self.outFile.write(" IMAGEQUALITY 95\n") self.outFile.write(" IMAGETYPE " + self.imageType + "\n") self.outFile.write(" OUTPUTFORMAT\n") self.outFile.write(" NAME " + self.imageType + "\n") self.outFile.write(" DRIVER 'GD/" + self.imageType.upper() + "'\n") self.outFile.write(" MIMETYPE 'image/" + lower(self.imageType) + "'\n") self.outFile.write(" #IMAGEMODE PC256\n") self.outFile.write(" EXTENSION '" + lower(self.imageType) + "'\n") self.outFile.write(" END\n") # Write Projection section def writeProjectionSection(self): # Need to get the destination srs from one of the map layers since # the project file doesn't contain the epsg id or proj4 text for # the map apart from that defined in each layer self.outFile.write(" PROJECTION\n") # Get the proj4 text from the first map layer's destination SRS destsrs = self.qgs.getElementsByTagName("destinationsrs")[0] proj4Text = destsrs.getElementsByTagName("proj4")[0].childNodes[0].nodeValue.encode('utf-8') # the proj4 text string needs to be reformatted to make mapserver happy self.outFile.write(self.formatProj4(proj4Text)) self.outFile.write(" END\n\n") # Write the LEGEND section def writeLegendSection(self): self.outFile.write(" # Legend\n") self.outFile.write(" LEGEND\n") self.outFile.write(" IMAGECOLOR 255 255 255\n") self.outFile.write(" STATUS ON\n") self.outFile.write(" KEYSIZE 18 12\n") self.outFile.write(" LABEL\n") self.outFile.write(" TYPE BITMAP\n") self.outFile.write(" SIZE MEDIUM\n") self.outFile.write(" COLOR 0 0 89\n") self.outFile.write(" END\n") self.outFile.write(" END\n\n") # Write the symbol definitions def writeSymbolSection(self): for symbol in self.symbolQueue.keys(): self.outFile.write( self.symbolQueue[symbol] ) self.outFile.write( "\n" ) # Write the WEB section of the map file def writeWebSection(self): self.outFile.write(" # Web interface definition. Only the template parameter\n") self.outFile.write(" # is required to display a map. See MapServer documentation\n") self.outFile.write(" WEB\n") self.outFile.write(" # Set IMAGEPATH to the path where MapServer should\n") self.outFile.write(" # write its output.\n") self.outFile.write(" IMAGEPATH '/tmp/'\n") self.outFile.write("\n") self.outFile.write(" # Set IMAGEURL to the url that points to IMAGEPATH\n") self.outFile.write(" # as defined in your web server configuration\n") self.outFile.write(" IMAGEURL '/tmp/'\n") self.outFile.write("\n") # TODO allow user to configure this self.outFile.write(" # WMS server settings\n") self.outFile.write(" METADATA\n") self.outFile.write(" 'wms_title' '" + self.mapName + "'\n") self.outFile.write(" 'wms_onlineresource' 'http://my.host.com/cgi-bin/mapserv?map=wms.map&'\n") self.outFile.write(" 'wms_srs' 'EPSG:4326'\n") self.outFile.write(" END\n\n") self.outFile.write(" #Scale range at which web interface will operate\n") if self.minimumScale != "": self.outFile.write(" MINSCALE " + self.minimumScale + "\n") if self.maximumScale != "": self.outFile.write(" MAXSCALE " + self.maximumScale + "\n") self.outFile.write(" # Template and header/footer settings\n") self.outFile.write(" # Only the template parameter is required to display a map. See MapServer documentation\n") if self.template != "": self.outFile.write(" TEMPLATE '" + self.template + "'\n") if self.header != "": self.outFile.write(" HEADER '" + self.header + "'\n") if self.footer != "": self.outFile.write(" FOOTER '" + self.footer + "'\n") self.outFile.write(" END\n\n") def parsePostgisConnection( self, dataString ): pg = {} pg['host'] = 'localhost' pg['dbname'] = 'gisdata' pg['user'] = '' pg['password'] = '' pg['table'] = '' pg['geom'] = 'the_geom' whereCondition = dataString.split("sql")[1][1:] cmp = dataString.split("sql")[0].split(" ") for c in cmp: if c[:1] == "(": pg['geom'] = c[1:][:-1] else: kvp = c.split("=") if (len(kvp) >= 2): pg[kvp[0]] = kvp[1] connString = 'host=' + pg['host'] + " user=" + pg['user'] if (len(pg['password'].replace("\'", "")) > 0): connString += " password=" + pg['password'].replace("'", "") connString += " dbname=" + pg['dbname'] dataString = pg['geom'] + " FROM " + pg['table'].replace("\"", "") filterString = whereCondition.replace("\"", "") return (connString, dataString, filterString) # Write the map layers - we have to defer writing to disk so we # can invert the order of the layes, since they are opposite in QGIS # compared to mapserver def writeMapLayers(self): # get the list of legend nodes so the layers can be written in the # proper order legend_nodes = self.qgs.getElementsByTagName("legendlayer") self.z_order = list() for legend_node in legend_nodes: self.z_order.append(legend_node.getAttribute("name").encode('utf-8').replace("\"", "")) # get the list of maplayer nodes maplayers = self.qgs.getElementsByTagName("maplayer") print "Processing ", len(maplayers), " layers" count = 0 layer_list = dict() for lyr in maplayers: count += 1 print "Processing layer ", count # The attributes of the maplayer tag contain the scale dependent settings, # visibility, and layer type layer_def = " LAYER\n" # store name of the layer layer_name = lyr.getElementsByTagName("layername")[0].childNodes[0].nodeValue.encode('utf-8').replace("\"", "") # first check to see if there is a name if len(lyr.getElementsByTagName("layername")[0].childNodes) > 0: layer_def += " NAME '" + lyr.getElementsByTagName("layername")[0].childNodes[0].nodeValue.encode('utf-8').replace("\"", "") + "'\n" else: # if no name for the layer, manufacture one layer_def += " NAME 'LAYER%s'\n" % count if lyr.getAttribute("type").encode('utf-8') == 'vector': layer_def += " TYPE " + lyr.getAttribute("geometry").encode('utf-8').upper() + "\n" elif lyr.getAttribute("type").encode('utf-8') == 'raster': layer_def += " TYPE " + lyr.getAttribute("type").encode('utf-8').upper() + "\n" # Set min/max scales if lyr.getAttribute('hasScaleBasedVisibilityFlag').encode('utf-8') == 1: layer_def += " MINSCALE " + lyr.getAttribute('minimumScale').encode('utf-8') + "\n" layer_def += " MAXSCALE " + lyr.getAttribute('maximumScale').encode('utf-8') + "\n" # data dataString = lyr.getElementsByTagName("datasource")[0].childNodes[0].nodeValue.encode('utf-8') # test if it is a postgis, grass or WMS layer # is there a better way to do this? probably. try: providerString = lyr.getElementsByTagName("provider")[0].childNodes[0].nodeValue.encode('utf-8') except: # if providerString is null providerString = '' if providerString == 'postgres': # it's a postgis layer (pgConnString, sqlData, sqlFilter) = self.parsePostgisConnection(dataString) layer_def += " CONNECTIONTYPE postgis\n" layer_def += " CONNECTION '" + pgConnString + "'\n" layer_def += " DATA '" + sqlData + "'\n" # don't write the filter keyword if there isn't one if sqlFilter: layer_def += " FILTER '" + sqlFilter + "'\n" elif providerString == 'wms' and lyr.getAttribute("type").encode('utf-8').upper() == 'RASTER': # it's a WMS layer layer_def += " CONNECTIONTYPE WMS\n" layer_def += " CONNECTION '" + dataString + "'\n" rasterProp = lyr.getElementsByTagName("rasterproperties")[0] # loop thru wmsSubLayers wmsSubLayers = rasterProp.getElementsByTagName('wmsSublayer') wmsNames = [] wmsStyles = [] for wmsLayer in wmsSubLayers: wmsNames.append( wmsLayer.getElementsByTagName('name')[0].childNodes[0].nodeValue.encode('utf-8').replace("\"", "") ) try: wmsStyles.append( wmsLayer.getElementsByTagName('style')[0].childNodes[0].nodeValue.encode('utf-8') ) except: wmsStyles.append( '' ) # Create necesssary wms metadata format = rasterProp.getElementsByTagName('wmsFormat')[0].childNodes[0].nodeValue.encode('utf-8') layer_def += " METADATA\n" layer_def += " 'wms_name' '" + ','.join(wmsNames) + "'\n" layer_def += " 'wms_server_version' '1.1.1'\n" try: ct = lyr.getElementsByTagName('coordinatetransform')[0] srs = ct.getElementsByTagName('sourcesrs')[0].getElementsByTagName('spatialrefsys')[0] epsg = srs.getElementsByTagName('epsg')[0].childNodes[0].nodeValue.encode('utf-8') layer_def += " 'wms_srs' 'EPSG:4326 EPSG:" + epsg + "'\n" except: pass layer_def += " 'wms_format' '" + format + "'\n" layer_def += " 'wms_style' '" + ','.join(wmsStyles) + "'\n" layer_def += " END\n" else: # its a standard ogr, gdal or grass layer layer_def += " DATA '" + dataString + "'\n" # WMS settings for all layers layer_def += " METADATA\n" layer_def += " 'wms_title' '" + lyr.getElementsByTagName("layername")[0].childNodes[0].nodeValue.encode('utf-8').replace("\"", "") + "'\n" layer_def += " END\n" layer_def += " STATUS DEFAULT\n" opacity = int ( 100.0 * float(lyr.getElementsByTagName("transparencyLevelInt")[0].childNodes[0].nodeValue.encode('utf-8')) / 255.0 ) layer_def += " TRANSPARENCY " + str(opacity) + "\n" layer_def += " PROJECTION\n" # Get the destination srs for this layer and use it to create # the projection section destsrs = self.qgs.getElementsByTagName("destinationsrs")[0] proj4Text = destsrs.getElementsByTagName("proj4")[0].childNodes[0].nodeValue.encode('utf-8') # the proj4 text string needs to be reformatted to make mapserver happy layer_def += self.formatProj4(proj4Text) layer_def += " END\n" scaleDependent = lyr.getAttribute("hasScaleBasedVisibilityFlag").encode('utf-8') if scaleDependent == '1': # get the min and max scale settings minscale = lyr.getAttribute("minimumScale").encode('utf-8') maxscale = lyr.getAttribute("maximumScale").encode('utf-8') if minscale > '': layer_def += " MINSCALE " + minscale + "\n" if maxscale > '': layer_def += " MAXSCALE " + maxscale + "\n" # Check for label field (ie LABELITEM) and label status try: labelOn = lyr.getElementsByTagName( "label")[0].childNodes[0].nodeValue.encode('utf-8') labelField = lyr.getElementsByTagName("labelfield")[0].childNodes[0].nodeValue.encode('utf-8') if labelField != '' and labelField is not None and labelOn == "1": layer_def += " LABELITEM '" + labelField + "'\n" except: # no labels pass # write the CLASS section for rendering # First see if there is a single symbol renderer if lyr.getElementsByTagName("singlesymbol").length > 0: symbolNode = lyr.getElementsByTagName("singlesymbol")[0].getElementsByTagName('symbol')[0] layer_def += self.simpleRenderer(lyr, symbolNode) elif lyr.getElementsByTagName("graduatedsymbol").length > 0: layer_def += self.graduatedRenderer(lyr, lyr.getElementsByTagName("graduatedsymbol")[0].getElementsByTagName('symbol')[0] ) elif lyr.getElementsByTagName("continuoussymbol").length > 0: layer_def += self.continuousRenderer(lyr, lyr.getElementsByTagName("continuoussymbol")[0] ) elif lyr.getElementsByTagName("uniquevalue").length > 0: layer_def += self.uniqueRenderer(lyr, lyr.getElementsByTagName("uniquevalue")[0].getElementsByTagName('symbol')[0] ) # end of LAYER layer_def += " END\n\n" # add the layer to the list layer_list[layer_name] = layer_def # all layers have been processed, reverse the list and write # not necessary since z-order is mapped by the legend list order self.z_order.reverse() for layer in self.z_order: self.outFile.write(layer_list[layer]) # Simple renderer ouput # We need the layer node and symbol node def simpleRenderer(self, layerNode, symbolNode): # get the layers geometry type geometry = layerNode.getAttribute("geometry").encode('utf-8').upper() class_def = " CLASS\n" class_def += " NAME '" + layerNode.getElementsByTagName("layername")[0].childNodes[0].nodeValue.encode('utf-8').replace("\"", "") + "' \n" class_def += " STYLE\n" # use the point symbol map to lookup the mapserver symbol type symbol = self.msSymbol( geometry, symbolNode ) class_def += " SYMBOL " + symbol + " \n" class_def += " SIZE " + symbolNode.getElementsByTagName('pointsize')[0].childNodes[0].nodeValue.encode('utf-8') + " \n" # outline color outlineNode = symbolNode.getElementsByTagName('outlinecolor')[0] class_def += " OUTLINECOLOR " + outlineNode.getAttribute('red') + ' ' + outlineNode.getAttribute('green') + ' ' + outlineNode.getAttribute('blue') + "\n" # color colorNode = symbolNode.getElementsByTagName('fillcolor')[0] class_def += " COLOR " + colorNode.getAttribute('red') + ' ' + colorNode.getAttribute('green') + ' ' + colorNode.getAttribute('blue') + "\n" class_def += " END\n" class_def += self.msLabel( layerNode ) # end of CLASS class_def += " END\n" return class_def # Graduated symbol renderer output def graduatedRenderer(self, layerNode, symbolNode): # get the layers geometry type geometry = layerNode.getAttribute("geometry").encode('utf-8').upper() # get the renderer field for building up the classes classField = layerNode.getElementsByTagName('classificationattribute')[0].childNodes[0].nodeValue.encode('utf-8') # write the render item class_def = " CLASSITEM '" + classField + "'\n" # write the rendering info for each class classes = layerNode.getElementsByTagName('symbol') for cls in classes: class_def += " CLASS\n" lower = cls.getElementsByTagName('lowervalue')[0].childNodes[0].nodeValue.encode('utf-8') upper = cls.getElementsByTagName('uppervalue')[0].childNodes[0].nodeValue.encode('utf-8') # If there's a label use it, otherwise autogenerate one try: label = cls.getElementsByTagName('label')[0].childNodes[0].nodeValue.encode('utf-8') class_def += " NAME '" + label + "'\n" except: class_def += " NAME '" + lower + " < " + classField + " < " + upper + "'\n" class_def += " EXPRESSION ( ([" + classField + "] >= " + lower + ") AND ([" + classField + "] <= " + upper + ") )\n" class_def += " STYLE\n" symbol = self.msSymbol( geometry, symbolNode ) class_def += " SYMBOL " + symbol + "\n" # Symbol size if geometry == 'POINT' or geometry == 'LINE': class_def += " SIZE " + cls.getElementsByTagName('pointsize')[0].childNodes[0].nodeValue.encode('utf-8') + " \n" # outline color outlineNode = cls.getElementsByTagName('outlinecolor')[0] class_def += " OUTLINECOLOR " + outlineNode.getAttribute('red') + ' ' + outlineNode.getAttribute('green') + ' ' + outlineNode.getAttribute('blue') + "\n" # color colorNode = cls.getElementsByTagName('fillcolor')[0] class_def += " COLOR " + colorNode.getAttribute('red') + ' ' + colorNode.getAttribute('green') + ' ' + colorNode.getAttribute('blue') + "\n" class_def += " END\n" # label class_def += self.msLabel( layerNode ) # end of CLASS class_def += " END\n" return class_def # Continuous symbol renderer output def continuousRenderer(self, layerNode, symbolNode): # get the layers geometry type geometry = layerNode.getAttribute("geometry").encode('utf-8').upper() # get the renderer field for building up the classes classField = layerNode.getElementsByTagName('classificationattribute')[0].childNodes[0].nodeValue.encode('utf-8') # write the rendering info for each class class_def += " CLASS\n" # Class name irrelevant for color ramps since mapserver can't render their legend #self.outFile.write(" NAME '" + classField + "'\n") # color lower = symbolNode.getElementsByTagName('lowestsymbol')[0].getElementsByTagName('symbol')[0] upper = symbolNode.getElementsByTagName('highestsymbol')[0].getElementsByTagName('symbol')[0] lowerColor = lower.getElementsByTagName('fillcolor')[0] upperColor = upper.getElementsByTagName('fillcolor')[0] # outline color outlineNode = lower.getElementsByTagName('outlinecolor')[0] class_def += " STYLE\n" # The first and last color of the ramp ( r g b r g b ) class_def += " COLORRANGE " + lowerColor.getAttribute('red') + " " + lowerColor.getAttribute('green') + " " + lowerColor.getAttribute('blue') + " " + upperColor.getAttribute('red') + " " + upperColor.getAttribute('green') + " " + upperColor.getAttribute('blue') + "\n" # The range of values over which to ramp the colors class_def += " DATARANGE " + lower.getElementsByTagName('lowervalue')[0].childNodes[0].nodeValue.encode('utf-8') + ' ' + upper.getElementsByTagName('lowervalue')[0].childNodes[0].nodeValue.encode('utf-8') + '\n' class_def += " RANGEITEM '" + classField + "'\n" class_def += " END\n" class_def += " STYLE\n" class_def += " OUTLINECOLOR " + outlineNode.getAttribute('red') + " " + outlineNode.getAttribute('green') + " " + outlineNode.getAttribute('blue') + "\n" class_def += " END\n" # label class_def += self.msLabel( layerNode ) # end of CLASS class_def += " END\n" return class_def # Unique value renderer output def uniqueRenderer(self, layerNode, symbolNode): # get the renderer field for building up the classes classField = layerNode.getElementsByTagName('classificationattribute')[0].childNodes[0].nodeValue.encode('utf-8') # get the layers geometry type geometry = layerNode.getAttribute("geometry").encode('utf-8').upper() # write the render item class_def = " CLASSITEM '" + classField + "'\n" # write the rendering info for each class classes = layerNode.getElementsByTagName('symbol') for cls in classes: class_def += " CLASS\n" try: lower = cls.getElementsByTagName('lowervalue')[0].childNodes[0].nodeValue.encode('utf-8') except IndexError: # set to blank in the case where the field used for rendering has no value lower = "" # If there's a label use it, otherwise autogenerate one try: label = cls.getElementsByTagName('label')[0].childNodes[0].nodeValue.encode('utf-8') class_def += " NAME '" + label + "'\n" except: class_def += " NAME '" + classField + " = " + lower + "' \n" class_def += " EXPRESSION '" + lower + "' \n" # Get the symbol name symbol = self.msSymbol( geometry, symbolNode ) class_def += " STYLE\n" class_def += " SYMBOL " + symbol + "\n" # Symbol size if geometry == 'POINT' or geometry == 'LINE': class_def += " SIZE " \ + cls.getElementsByTagName('pointsize')[0].childNodes[0].nodeValue.encode('utf-8') \ + " \n" # outline color outlineNode = cls.getElementsByTagName('outlinecolor')[0] class_def += " OUTLINECOLOR " \ + outlineNode.getAttribute('red') + ' ' \ + outlineNode.getAttribute('green') + ' ' \ + outlineNode.getAttribute('blue') \ + "\n" # color colorNode = cls.getElementsByTagName('fillcolor')[0] class_def += " COLOR " \ + colorNode.getAttribute('red') + ' ' \ + colorNode.getAttribute('green') + ' ' \ + colorNode.getAttribute('blue') \ + "\n" class_def += " END\n" # label class_def += self.msLabel( layerNode ) # end of CLASS class_def += " END\n" return class_def # Utility method to format a proj4 text string into mapserver format def formatProj4(self, proj4text): parms = proj4text.split(" ") ret = "" for p in parms: p = p.replace("+","") ret = ret + " '" + p + "'\n" return ret # Determines the symbol name and adds it to the symbol queue def msSymbol(self, geometry, symbolNode): # contains the same markup for a layer regardless of type # so we infer a symbol type based on the geometry symbolName = '' symbol = '0' if geometry == 'POLYGON': symbol = '0' elif geometry == 'LINE': symbol = '0' elif geometry == 'POINT': try: symbolName = qgisSymbols[symbolNode.getElementsByTagName('pointsymbol')[0].childNodes[0].nodeValue.encode('utf-8')] except: symbolName = "CIRCLE" # make sure it's single quoted symbol = "'" + symbolName + "'" if symbolName == 'CIRCLE': self.symbolQueue['CIRCLE'] = """ #Circle symbol SYMBOL NAME 'CIRCLE' TYPE ellipse FILLED true POINTS 1 1 END END """ if symbolName == 'TRIANGLE': self.symbolQueue['TRIANGLE'] = """ SYMBOL NAME "TRIANGLE" TYPE vector FILLED true POINTS 0 1 .5 0 1 1 0 1 END END """ return symbol # Label block creation # TODO field-based parameters, alignment, truetype fonts, sizes def msLabel(self, layerNode): # currently a very basic bitmap font labelNode = layerNode.getElementsByTagName('labelattributes')[0] labelField = labelNode.getElementsByTagName('label')[0].getAttribute('field').encode('utf-8') if labelField != '' and labelField is not None: labelBlock = " LABEL \n" labelBlock += " SIZE medium\n" labelBlock += " COLOR 0 0 0 \n" # Include label angle if specified # Note that angles only work for truetype fonts which aren't supported yet angle = labelNode.getElementsByTagName('angle')[0].getAttribute('value').encode('utf-8') labelBlock += " ANGLE " + angle + "\n" # Include label buffer if specified # Note that the buffer has different meaning in qgis vs mapserver # mapserver just adds blank space around the label while # qgis uses a fill color around the label # Note that buffer only works for truetype fonts which aren't supported yet buffer = labelNode.getElementsByTagName('buffersize')[0].getAttribute('value').encode('utf-8') labelBlock += " BUFFER " + buffer + "\n" labelBlock += " END \n" return labelBlock else: return ''