예제 #1
0
    def initGui(self):
        # Create action that will start plugin configuration
        self.action = QAction(QIcon(":/plugins/simplesvg/icon.png"), \
                "Save as SVG", self.iface.mainWindow())
        # connect the action to the run method
        QObject.connect(self.action, SIGNAL("activated()"), self.run)

        # Add toolbar button and menu item
        self.iface.addToolBarIcon(self.action)
        self.dlg = SimpleSvgDialog(self.iface)
        self.dlg.setFilePath(self.svgFilename)
        QObject.connect(self.dlg, SIGNAL("showHelp()"), self.showHelp)
        QObject.connect(self.dlg, SIGNAL("accepted()"), self.writeToFile)
        QObject.connect(self.dlg, SIGNAL("cbFeaturesInMapcanvasOnlyChanged"),
                        self.setFeaturesInMapcanvasOnly)

        # about
        self.aboutAction = QAction(QIcon(":/plugins/simplesvg/help.png"), \
                              "About", self.iface.mainWindow())
        self.aboutAction.setWhatsThis("SimpleSvg Plugin About")
        QObject.connect(self.aboutAction, SIGNAL("activated()"), self.about)
        # help
        self.helpAction = QAction(QIcon(":/plugins/simplesvg/help.png"), \
                              "Help", self.iface.mainWindow())
        self.helpAction.setWhatsThis("SimpleSvg Plugin Help")
        QObject.connect(self.helpAction, SIGNAL("activated()"), self.showHelp)
        if hasattr(self.iface, "addPluginToWebMenu"):
            self.iface.addPluginToWebMenu("&Save as SVG", self.action)
            self.iface.addPluginToWebMenu("&Save as SVG", self.aboutAction)
            self.iface.addPluginToWebMenu("&Save as SVG", self.helpAction)
        else:
            self.iface.addPluginToMenu("&Save as SVG", self.action)
            self.iface.addPluginToMenu("&Save as SVG", self.aboutAction)
            self.iface.addPluginToMenu("&Save as SVG", self.helpAction)
예제 #2
0
  def initGui(self):
      # Create action that will start plugin configuration
    self.action = QAction(QIcon(":/plugins/simplesvg/icon.png"), \
            "Save as SVG", self.iface.mainWindow())
    # connect the action to the run method
    QObject.connect(self.action, SIGNAL("activated()"), self.run)

    # Add toolbar button and menu item
    self.iface.addToolBarIcon(self.action)
    self.dlg = SimpleSvgDialog(self.iface)
    self.dlg.setFilePath(self.svgFilename)
    QObject.connect(self.dlg, SIGNAL("showHelp()"), self.showHelp)
    QObject.connect(self.dlg, SIGNAL("accepted()"), self.writeToFile)
    QObject.connect(self.dlg, SIGNAL("cbFeaturesInMapcanvasOnlyChanged"), self.setFeaturesInMapcanvasOnly)

    # about
    self.aboutAction = QAction(QIcon(":/plugins/simplesvg/help.png"), \
                          "About", self.iface.mainWindow())
    self.aboutAction.setWhatsThis("SimpleSvg Plugin About")
    QObject.connect(self.aboutAction, SIGNAL("activated()"), self.about)
    # help
    self.helpAction = QAction(QIcon(":/plugins/simplesvg/help.png"), \
                          "Help", self.iface.mainWindow())
    self.helpAction.setWhatsThis("SimpleSvg Plugin Help")
    QObject.connect(self.helpAction, SIGNAL("activated()"), self.showHelp)
    if hasattr ( self.iface, "addPluginToWebMenu" ):
        self.iface.addPluginToWebMenu("&Save as SVG", self.action)
        self.iface.addPluginToWebMenu("&Save as SVG", self.aboutAction)
        self.iface.addPluginToWebMenu("&Save as SVG", self.helpAction)
    else:
        self.iface.addPluginToMenu("&Save as SVG", self.action)
        self.iface.addPluginToMenu("&Save as SVG", self.aboutAction)
        self.iface.addPluginToMenu("&Save as SVG", self.helpAction)
예제 #3
0
class SimpleSvg:

  MSG_BOX_TITLE = "QGIS SimpleSvg Plugin "

  def __init__(self, iface):
    # Save reference to the QGIS interface
    self.iface = iface
    self.svgFilename = QSettings().value('/simplesvg/lastfile', '')
    self.svgType = SVG_TYPE_PATH
    self.strokeLineJoin = 'round' # miter, round, bevel
    # normal usage: current scale, only the features which touch current mapcanvas
    # if setting this false, ALL features will be taken from the dataprovider
    # and rendered as vectors, NOTE: not working for raster layers !
    self.featuresInMapcanvasOnly = True

  def initGui(self):
      # Create action that will start plugin configuration
    self.action = QAction(QIcon(":/plugins/simplesvg/icon.png"), \
            "Save as SVG", self.iface.mainWindow())
    # connect the action to the run method
    QObject.connect(self.action, SIGNAL("activated()"), self.run)

    # Add toolbar button and menu item
    self.iface.addToolBarIcon(self.action)
    self.dlg = SimpleSvgDialog(self.iface)
    self.dlg.setFilePath(self.svgFilename)
    QObject.connect(self.dlg, SIGNAL("showHelp()"), self.showHelp)
    QObject.connect(self.dlg, SIGNAL("accepted()"), self.writeToFile)
    QObject.connect(self.dlg, SIGNAL("cbFeaturesInMapcanvasOnlyChanged"), self.setFeaturesInMapcanvasOnly)

    # about
    self.aboutAction = QAction(QIcon(":/plugins/simplesvg/help.png"), \
                          "About", self.iface.mainWindow())
    self.aboutAction.setWhatsThis("SimpleSvg Plugin About")
    QObject.connect(self.aboutAction, SIGNAL("activated()"), self.about)
    # help
    self.helpAction = QAction(QIcon(":/plugins/simplesvg/help.png"), \
                          "Help", self.iface.mainWindow())
    self.helpAction.setWhatsThis("SimpleSvg Plugin Help")
    QObject.connect(self.helpAction, SIGNAL("activated()"), self.showHelp)
    if hasattr ( self.iface, "addPluginToWebMenu" ):
        self.iface.addPluginToWebMenu("&Save as SVG", self.action)
        self.iface.addPluginToWebMenu("&Save as SVG", self.aboutAction)
        self.iface.addPluginToWebMenu("&Save as SVG", self.helpAction)
    else:
        self.iface.addPluginToMenu("&Save as SVG", self.action)
        self.iface.addPluginToMenu("&Save as SVG", self.aboutAction)
        self.iface.addPluginToMenu("&Save as SVG", self.helpAction)

  def setFeaturesInMapcanvasOnly(self, checked):
    if not checked:
        QMessageBox.information(self.dlg, "Warning", "Be carefull: unchecking this, means QGIS is going to fetch ALL objects from your data.\nHandle with care for big datasets.")
    self.featuresInMapcanvasOnly = checked

  def showHelp(self):
    docFile = os.path.join(os.path.dirname(__file__), "docs","index.html")
    QDesktopServices.openUrl( QUrl("file:" + docFile) )

  def writeToFile(self):
      self.svgFilename = self.dlg.getFilePath()
      # save this filename in settings for later
      QSettings().setValue('/simplesvg/lastfile', self.svgFilename)
      output = self.writeSVG()
      file = open(self.svgFilename, "w")
      #print output
      for line in output:
          #print '%s - %s' % (type(line),line)
          file.write(line.encode('utf-8'))
      file.close()
      QMessageBox.information(self.iface.mainWindow(), \
              "SimpleSvg Plugin", "Finished writing to svg")

  def about(self):
    try:
        infoString = QString("Written by Richard Duivenvoorde\nEmail - [email protected]\n")
        infoString = infoString.append("Company - http://www.webmapper.net\n")
        infoString = infoString.append("Source: http://github.com/rduivenvoorde/simplesvg/")
    except NameError:
        infoString = "Written by Richard Duivenvoorde\nEmail - [email protected]\n"
        infoString += "Company - http://www.webmapper.net\n"
        infoString += "Source: http://github.com/rduivenvoorde/simplesvg/"
    QMessageBox.information(self.iface.mainWindow(), \
              "SimpleSvg Plugin About", infoString)

  def unload(self):
    # Remove the plugin menu item and icon
    if hasattr ( self.iface, "addPluginToWebMenu" ):
        self.iface.removePluginWebMenu("&Save as SVG",self.action)
        self.iface.removePluginWebMenu("&Save as SVG",self.helpAction)
        self.iface.removePluginWebMenu("&Save as SVG",self.aboutAction)
    else:
        self.iface.removePluginMenu("&Save as SVG",self.action)
        self.iface.removePluginMenu("&Save as SVG",self.helpAction)
        self.iface.removePluginMenu("&Save as SVG",self.aboutAction)

    self.iface.removeToolBarIcon(self.action)

    QObject.disconnect(self.aboutAction, SIGNAL("activated()"), self.about)
    QObject.disconnect(self.helpAction, SIGNAL("activated()"), self.showHelp)
    QObject.disconnect(self.action, SIGNAL("activated()"), self.run)
    QObject.disconnect(self.dlg, SIGNAL("accepted()"), self.writeToFile)

  # run method that performs all the real work
  def run(self):
    self.dlg.show()

  def writeSVG(self):
    # determine extent for later use (only write geoms that are at least partially contained)
    self.currentExtent = self.iface.mapCanvas().extent()
    w=self.iface.mapCanvas().size().width()
    h=self.iface.mapCanvas().size().height()
    # keep the current extent as a Geometry to be able to do some 'contains' tests later
    self.extentAsPoly = QgsGeometry();
    self.extentAsPoly = QgsGeometry.fromRect(self.currentExtent);

    svg = [u'<?xml version="1.0" standalone="no"?>\n']
    svg.append(u'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n')
    svg.append(u'<svg xmlns="http://www.w3.org/2000/svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox = "0 0 '+str(w)+' '+str(h)+'" version = "1.1">\n')
    svg.append(u'<!-- svg generated using QGIS www.qgis.org -->\n')

    # for all visible layers, from bottom to top (-1)
    for i in range (self.iface.mapCanvas().layerCount()-1, -1, -1):
        layer = self.iface.mapCanvas().layer(i)
        if layer.type()==0: # vector
          if self.isRendererV2(layer):
            #QMessageBox.information(self.iface.mainWindow(), "Warning", "New Symbology layer found for layer '"+layer.name()+"'\n\nThe plugin cannot handle layer(s) which use 'New Symbology' yet.\n\nThis layer will be ignored in export.\n\nPlease change symbology of these layer(s) to 'Old Symbology' if you want this layer in svg.")
            #pass
            svg.extend(self.writeVectorLayer(layer, False))
          else: # old symbology
            svg.extend(self.writeVectorLayer(layer, False))
        elif layer.type()==1: # raster
          svg.extend(self.writeRaster(layer))
        # layers like OpenLayers/OpenStreetmap/Google are plugin layer: write as raster for now
        elif layer.type()==2: # plugin layer 
          svg.extend(self.writeRaster(layer))

    # now layers with labels
    for i in range (self.iface.mapCanvas().layerCount()-1, -1, -1):
        layer = self.iface.mapCanvas().layer(i)
        if layer.type()==0: # vector
          lblSettings = QgsPalLayerSettings()
          lblSettings.readFromLayer( layer )
        #TODO: fix this if layer.type()==0 and layer.hasLabelsEnabled(): # only vectors have labels
        if layer.type()==0 and lblSettings.enabled: # only vectors have labels
          svg.extend(self.writeVectorLayer(layer, True))

    # qgis extent, usable for clipping in Inkscape
    svg.extend(self.writeExtent())
    svg.append(u'</svg>')
    return svg

  def isRendererV2(self, layer):
    return (layer.type()==0 and hasattr(layer, 'isUsingRendererV2') and layer.isUsingRendererV2()) or (layer.type()==0 and not hasattr(layer, 'isUsingRendererV2') and ('rendererV2' in dir(layer)))

  def isRendererV2SIP2(self, layer):
    return (layer.type()==0 and not hasattr(layer, 'isUsingRendererV2') and ('rendererV2' in dir(layer)))

  def writeVectorLayer(self, layer, labels=False):
    # in case of 'on the fly projection' 
    # AND 
    # different crs's for mapCanvas/project and layer we have to reproject stuff
    if hasattr(self.iface.mapCanvas().mapRenderer(), "destinationSrs"):
        # QGIS < 2.0
        destinationCrs = self.iface.mapCanvas().mapRenderer().destinationSrs()
        layerCrs = layer.srs()
    else:
        destinationCrs = self.iface.mapCanvas().mapRenderer().destinationCrs()
        layerCrs = layer.crs()
    if self.featuresInMapcanvasOnly:
        mapCanvasExtent = self.iface.mapCanvas().extent()
    else:
        mapCanvasExtent = layer.extent()
    #print 'destination crs: %s:' % destinationCrs.toProj4()
    #print 'layer crs:       %s:' % layerCrs.toProj4()
    doCrsTransform = False
    if not destinationCrs == layerCrs:
      # we have to transform the mapCanvasExtent to the data/layer Crs to be able
      # to retrieve the features from the data provider
      # but ONLY if we are working with on the fly projection
      # (because in that case we just 'fly' to the raw coordinates from data)
      if self.iface.mapCanvas().hasCrsTransformEnabled():
        # only if we have 'on te fly transformation' enabled
        #    AND the mapCanvasExtent is the real mapcanvas extent (note: if we
        # are going to write ALL features, then mapCanvasExtent is actually the layer extent)
        if self.featuresInMapcanvasOnly:
          crsTransform = QgsCoordinateTransform(destinationCrs, layerCrs)
          mapCanvasExtent = crsTransform.transformBoundingBox(mapCanvasExtent)
        # we have to have a transformer to do the transformation of the geometries
        # to the mapcanvas crs ourselves:
        crsTransform = QgsCoordinateTransform(layerCrs, destinationCrs)
        doCrsTransform = True

    lblSettings = QgsPalLayerSettings()
    lblSettings.readFromLayer( layer )

    # select features within current extent,
    #   with  ALL attributes, WITHIN currentExtent, WITH geom, AND using Intersect instead of bbox
    # we are going to group all features by their symbol so in svg we can group them in a <g> tag with the symbol style
    if self.isRendererV2(layer):
      if hasattr(layer, 'isUsingRendererV2'):
        # For QGis 1.8 API, new symbology
        provider = layer.dataProvider();
        provider.select(provider.attributeIndexes(), mapCanvasExtent, True, True)
      else:
        # For QGis 2.0 cleaned-up API
        provider = layer.getFeatures( QgsFeatureRequest().setFilterRect(mapCanvasExtent))
      renderer = layer.rendererV2()
      if str(renderer.type()) not in ("singleSymbol", "categorizedSymbol", "graduatedSymbol"):
        QMessageBox.information(self.iface.mainWindow(), "Warning", "New Symbology layer found for layer '"+layer.name()+"'\n\nThis layer uses a Renderer/Style which cannot be used with this plugin.\n\nThis layer will be ignored in export.")
        return ""
    else:
      # For QGis <= 1.8 API, old symbology
      provider = layer.dataProvider();
      provider.select(provider.attributeIndexes(), mapCanvasExtent, True, True)
      renderer = layer.renderer()
    symbols = renderer.symbols()
    symbolFeatureMap = dict.fromkeys(symbols, [])
    id=self.sanitizeStr(unicode(layer.name()).lower())
    if labels:
        id=id+'_labels'
    svg = [u'<g id="'+id+'" inkscape:groupmode="layer" inkscape:label="'+id+'">\n']; # start of layer g-element
    # now iterate through each feature and group by feature
    f = QgsFeature();
    feature = None
    #print "1 symbols holds %s symbols" % len(symbols)
    while provider.nextFeature(f):
      feature = QgsFeature(f)

      geom = feature.geometry()
      if hasattr(layer, "srs"):
        # QGIS < 2.0
        layerCrs = layer.srs()
      else:
        layerCrs = layer.crs()

      if doCrsTransform:
        if hasattr(geom, "transform"):
          geom.transform(crsTransform)
        else:
          QMessageBox.warning(self.iface.mainWindow(), self.MSG_BOX_TITLE, ("Cannot crs-transform geometry in your QGIS version ...\n" "Only QGIS version 1.5 and above can transform geometries on the fly\n" "As a workaround, you can try to save the layer in the destination crs (eg as shapefile) and reload that layer...\n"), QMessageBox.Ok, QMessageBox.Ok)
          break

      symbol = self.symbolForFeature(layer, feature)
      #print "feature: %s  symbol: %s rgb: %s %s %s" % (feature, symbol, symbol.color().red(), symbol.color().green(), symbol.color().blue())
      # Continous Color does NOT have all symbols, but ONLY start and end color
      # that's why we do some extra stuff here...
      # ONLY needed for Old Symbology (which have 'name()' and not 'type()')
      if hasattr(renderer, 'name') and renderer.name() == "Continuous Color":
        symbols.append(symbol)
        if symbol in symbolFeatureMap:
            symbolFeatureMap[symbol]=[feature]
        else:
            symbolFeatureMap.update({symbol:[feature]})
      else:
        if not symbol in symbolFeatureMap or len(symbolFeatureMap[symbol])==0:
          symbolFeatureMap[symbol]=[feature]
        else:
          symbolFeatureMap[symbol].append(feature)
    # now iterate over symbols IF there are any features in this view from this layer
    if feature != None:
      id=id+'_'
      i=0
      #print "2 symbols holds %s symbols" % len(symbols)
      for symbol in symbols:
        if self.isRendererV2(layer):
          sym = self.symbolV2(feature, symbol)
        else:
          sym = self.symbol(feature, symbol)
        # start of symbol g-element, holds colors and stroke etc
        if not labels:
          fill = ''
          if sym.has_key('fill'):
            fill = 'fill="' + sym['fill'] + '"'
          svg.append(u'<g stroke="' + sym['stroke'] + '" '+ fill + ' stroke-linejoin="' + self.strokeLineJoin + '" stroke-width="' + sym['stroke-width'] +'">\n')
        else:
          # TODO fix this
          if False:
            lc = layer.label().labelAttributes().color()
            lblColor = u'rgb(%s,%s,%s)' % (lc.red(), lc.green(), lc.blue())
          else:  # labels all black for now...
            lblColor = u'rgb(0,0,0)'
          svg.append(u'<g stroke="none" fill="'+lblColor+'">\n')
        for feature in symbolFeatureMap[symbol]:
          i=i+1
          # labeltxt is used both for the real labels, AND for the inkscape-label attributes of g and txt elements
          # TODO fix this
          if lblSettings.enabled:
            labeltxt = self.sanitizeStr(feature[lblSettings.fieldName])
          else:
            #labeltxt = self.sanitizeStr(layer.label().fieldValue(0, feature)) # only first field for now.
            #labeltxt = self.sanitizeStr(unicode(feature.fields().field(0)))
            labeltxt = self.sanitizeStr('')
          if not labels:
            svg.extend(self.writeFeature(feature, id+str(i), labeltxt))
          if labels:
            geom = feature.geometry().centroid()
            # centroid-method returns a NON-transformed centroid
            if doCrsTransform:
              if hasattr(geom, "transform"):
                geom.transform(crsTransform)
              else:
                QMessageBox.warning(self.iface.mainWindow(), self.MSG_BOX_TITLE, ("Cannot crs-transform geometry in your QGIS version ...\n" "Only QGIS version 1.5 and above can transform geometries on the fly\n" "As a workaround, you can try to save the layer in the destination crs (eg as shapefile) and reload that layer...\n"), QMessageBox.Ok, QMessageBox.Ok)
                break
            svg.extend(self.label2svg(geom.asPoint(), id+str(i), self.symbolForFeature(layer, feature), labeltxt))
        svg.append(u'</g>\n'); # end of symbol
    svg.append(u'</g>\n'); # end of layer
    return svg

  def symbol(self, feature, symbol):
    sym={}
    sc = symbol.color()
    sym['stroke'] = u'rgb(%s,%s,%s)' % (sc.red(), sc.green(), sc.blue())
    # fill color: only non line features have fill color, lines have 'none'
    geom = feature.geometry()
    if geom.wkbType() == QGis.WKBLineString or geom.wkbType() == QGis.WKBMultiLineString:
      sym['fill'] = u'none'
    else:
      f = symbol.fillColor()
      sym['fill'] = u'rgb(%s,%s,%s)' % (f.red(), f.green(), f.blue())
    # pen: in QT pen can be 0
    if symbol.pen().width() < 1:
      sym['stroke-width'] = u'0.5'
    else:
      sym['stroke-width'] = unicode(symbol.pen().width())
    return sym

  def symbolV2(self, feature, symbol):
    #print '##### symbol: %s, symbollayercount: %s' % (symbol, symbol.symbolLayerCount())
    sym={}
    if symbol.symbolLayerCount() > 1:
      QMessageBox.information(self.iface.mainWindow(), "Warning", "Layer '"+layer.name()+"' uses New Symbology, and styles with more the one Symbol Layer, only the first one will be use.")
    sl = symbol.symbolLayer(0)
    slprops = sl.properties()
    #print "symbollayer properties: %s" % slprops
    # region/polgyons have: color_border / style_border / offset / style / color / width_border
    #  {PyQt4.QtCore.QString(u'color_border'): PyQt4.QtCore.QString(u'0,0,0,255'), PyQt4.QtCore.QString(u'style_border'): PyQt4.QtCore.QString(u'solid'), PyQt4.QtCore.QString(u'offset'): PyQt4.QtCore.QString(u'0,0'), PyQt4.QtCore.QString(u'style'): PyQt4.QtCore.QString(u'solid'), PyQt4.QtCore.QString(u'color'): PyQt4.QtCore.QString(u'0,0,255,255'), PyQt4.QtCore.QString(u'width_border'): PyQt4.QtCore.QString(u'0.26')}
    # markers/points have : color_border / offset / size / color / name / angle:
    #  {PyQt4.QtCore.QString(u'color_border'): PyQt4.QtCore.QString(u'0,0,0,255'), PyQt4.QtCore.QString(u'offset'): PyQt4.QtCore.QString(u'0,0'), PyQt4.QtCore.QString(u'size'): PyQt4.QtCore.QString(u'2'), PyQt4.QtCore.QString(u'color'): PyQt4.QtCore.QString(u'255,0,0,255'), PyQt4.QtCore.QString(u'name'): PyQt4.QtCore.QString(u'circle'), PyQt4.QtCore.QString(u'angle'): PyQt4.QtCore.QString(u'0')}
    # lines have          : color / offset / penstyle / width / use_custom_dash / joinstyle / customdash / capstyle:
    #  {PyQt4.QtCore.QString(u'color'): PyQt4.QtCore.QString(u'255,255,0,255'), PyQt4.QtCore.QString(u'offset'): PyQt4.QtCore.QString(u'0'), PyQt4.QtCore.QString(u'penstyle'): PyQt4.QtCore.QString(u'solid'), PyQt4.QtCore.QString(u'width'): PyQt4.QtCore.QString(u'0.5'), PyQt4.QtCore.QString(u'use_custom_dash'): PyQt4.QtCore.QString(u'0'), PyQt4.QtCore.QString(u'joinstyle'): PyQt4.QtCore.QString(u'bevel'), PyQt4.QtCore.QString(u'customdash'): PyQt4.QtCore.QString(u'5;2'), PyQt4.QtCore.QString(u'capstyle'): PyQt4.QtCore.QString(u'square')}
    try:
        strokekey = QString(u'color_border')
        colorkey = QString(u'color')
        stylekey = QString(u'style')
        width_borderkey = QString(u'width_border')
        widthkey = QString(u'width')
    except NameError:
        strokekey = u'color_border'
        colorkey = u'color'
        stylekey = u'style'
        width_borderkey = u'width_border'
        widthkey = u'width'
    if slprops.has_key(strokekey):
      stroke = unicode(slprops[strokekey])
      sym['stroke'] = u'rgb(%s)' % (stroke[:stroke.rfind(',')])
    else:
      sym['stroke'] = u'none'
    # fill color: only non line features have fill color, lines have 'none'
    geom = feature.geometry()
    if slprops.has_key(colorkey):
      fill = unicode(slprops[colorkey])
      if geom.wkbType() == QGis.WKBLineString or geom.wkbType() == QGis.WKBMultiLineString:
        sym['stroke'] = u'rgb(%s)' % (fill[:fill.rfind(',')])
      # points have fill and stroke
      sym['fill'] = u'rgb(%s)' % (fill[:fill.rfind(',')])
    # if feature is line OR when there is no brush: set fill to none
    if geom.wkbType() == QGis.WKBLineString or geom.wkbType() == QGis.WKBMultiLineString or (slprops.has_key(stylekey) and slprops[stylekey] == 'no'):
      sym['fill'] = u'none'
    # pen: in QT pen can be 0
    if slprops.has_key(width_borderkey):
      sym['stroke-width'] = unicode(slprops[width_borderkey])
    elif slprops.has_key(widthkey):
      sym['stroke-width'] = unicode(slprops[widthkey])
    else:
      sym['stroke-width'] = u'0.26'
    #print sym
    return sym


  def writeExtent(self):
    svg = [u'<!-- QGIS extent for clipping, eg in Inkscape -->\n<g id="qgisviewbox" inkscape:groupmode="layer" inkscape:label="qgisviewbox" stroke="rgb(255,0,0)" stroke-width="1" fill="none" >\n']
    for ring in self.extentAsPoly.asPolygon():
        svg.append(u'<path d="M ')
        first = True
        for point in ring:
            pixpoint =  self.w2p(point.x(), point.y(), self.iface.mapCanvas().mapUnitsPerPixel(), self.currentExtent.xMinimum(), self.currentExtent.yMaximum())
            if not first:
                svg.append(u'L ')
            svg.append((unicode(pixpoint[0]) + ',' + unicode(pixpoint[1]) + ' '))
            first = False
        svg.append(u'" />\n')
    svg.append(u'</g>')
    return svg


  def writeRaster(self, layer):
    # hide all layers except 'layer' and save as png image in current directory
    # TODO? maybe inline it in svg?
    # save visibility of layers
    visibleList=self.iface.mapCanvas().layers()
    legend = self.iface.legendInterface()
    # set all layers invisible EXCEPT layer
    for lyr in visibleList:
      if lyr != layer:
        legend.setLayerVisible(lyr, False)
    lyrName = unicode(layer.name())
    imgName = lyrName+'.png'
    try:
        imgPath= self.svgFilename[:self.svgFilename.rfind('/')+1]
    except NameError:
        imgPath= self.svgFilename[:self.svgFilename.rfind('/')+1]
    # save image next to svg but put it in Image tag only the local filename
    self.iface.mapCanvas().saveAsImage(imgPath+imgName)
    # <image y="-7.7685061" x="27.115078" id="image3890" xlink:href="nl.png" />
    svg = [u'<g id="'+lyrName+'" inkscape:groupmode="layer" inkscape:label="'+lyrName+'">\n'];
    #svg.append('<image y="0" x="0" xlink:href="'+imgPath+imgName+'" />')
    svg.append(u'<image y="0" x="0" xlink:href="'+imgName+'" />')
    svg.append(u'</g>') # end of raster layer
    # now set earlier visible layers back to visible
    for lyr in visibleList:
      legend.setLayerVisible(lyr, True)
    return svg

  def label2svg(self, point, fid, symbol, labelTxt):
    # <g> <text x="262.08704" y="523.79077">abc</text> </g>
    #point = feature.geometry().centroid().asPoint()
    xy =  self.w2p(point.x(), point.y(), self.iface.mapCanvas().mapUnitsPerPixel(), self.currentExtent.xMinimum(), self.currentExtent.yMaximum())
    inkscapeLbl = ''
    if len(labelTxt)>0:
        inkscapeLbl = 'inkscape:label="'+unicode(labelTxt+'_lbl')+'"'
    svg = [u'<text id="'+fid+'" x="'+unicode(xy[0])+'" y="'+unicode(xy[1])+'" '+inkscapeLbl+'>'+unicode(labelTxt)+'</text>\n']
    return svg

  def sanitizeStr(self, string):
    # TODO: find the right way to do this
    return unicode(string).replace(' ','_').replace('/','_').replace(',','_').replace('.','_')

  def writeFeature(self, feature, fid, labelTxt):
    svg = []
    # <g>-element set's style attributes
    inkscapeLbl = ''
    if len(labelTxt)>0:
        inkscapeLbl = 'inkscape:label="'+unicode(labelTxt)+'"'
    svg.append(u'<g id="' + fid + '" '+inkscapeLbl+'>\n')
    geom=feature.geometry()
    currentExtent=self.currentExtent
    if geom.wkbType() == QGis.WKBPoint: # 1 = WKBPoint
        svg.extend(self.point2svg(feature, currentExtent))
    if geom.wkbType() == QGis.WKBPolygon: # 3 = WKBTYPE.WKBPolygon:
        polygon = geom.asPolygon()  # returns a list
        svg.extend(self.polygon2svg(feature, polygon, currentExtent))
    if geom.wkbType() == QGis.WKBMultiPolygon: # 6 = WKBTYPE.WKBMultiPolygon:
        multipolygon = geom.asMultiPolygon() # returns a list
        for polygon in multipolygon:
          svg.extend(self.polygon2svg(feature, polygon, currentExtent))
    if geom.wkbType() == QGis.WKBLineString: # 6 = WKBTYPE.WKBLineString:
        line = geom.asPolyline()  # returns a list of points
        svg.extend(self.line2svg(feature, line, currentExtent))
    if geom.wkbType() == QGis.WKBMultiLineString: # 6 = WKBTYPE.WKBLineString:
        multiline = geom.asMultiPolyline()  # returns a list of points
        for line in multiline:
            svg.extend(self.line2svg(feature, line, currentExtent))
    svg.append(u'</g>\n');
    return svg

  def point2svg(self, feature, currentExtent):
    point = feature.geometry().asPoint()
    xy =  self.w2p(point.x(), point.y(), self.iface.mapCanvas().mapUnitsPerPixel(), self.currentExtent.xMinimum(), self.currentExtent.yMaximum())
    # TODO take current extent into account
    svg = ['<circle cx="'+unicode(xy[0])+'" cy="'+unicode(xy[1])+'" r="5" />']
    return svg

  def symbolForFeature(self, layer, feature):
    if self.isRendererV2(layer):
        return layer.rendererV2().symbolForFeature(feature)
    else: 
      # symbolForFeatures seems not to work for Old Symbology?? Do it ourselves:
      # OLD symbolisation:
      #   Graduated Symbol: every symbol has BOTH upper and lower bound/value
      #   Unique Value: every symbol has BOTH upper and lower value
      #   Continues Color: HAS lower(==value) but NO upper value, BUT has just two symbols: MIN and MAX color, see http://doc.qgis.org/head/qgscontinuouscolorrenderer_8cpp-source.html
      #   Single Simbol: just one symbol, return it
      renderer = layer.renderer()
      #print "renderer.name(): %s" % renderer.name()
      default = None
      if renderer.name() == "Single Symbol":   # there is just one symbol: return it
        return renderer.symbols()[0]
      if renderer.name() == "Continuous Color":
        #pass  # already done, should not come here !!
        minSymbol = renderer.symbols()[0]
        minValue = (minSymbol.lowerValue()).toDouble()[0]  # we know Continuous Color only works with numeric attributes
        minRed = minSymbol.fillColor().red()
        minGreen = minSymbol.fillColor().green()
        minBlue = minSymbol.fillColor().blue()
        maxSymbol = renderer.symbols()[1]
        maxValue = (maxSymbol.lowerValue()).toDouble()[0]  # we know Continuous Color only works with numeric attributes
        maxRed = maxSymbol.fillColor().red()
        maxGreen = maxSymbol.fillColor().green()
        maxBlue = maxSymbol.fillColor().blue()
        # create new symbol and set RGB according to calculation in http://doc.qgis.org/head/qgscontinuouscolorrenderer_8cpp-source.html
        symbol = QgsSymbol(minSymbol) # copy
        value = (feature.attributeMap()[renderer.classificationAttributes()[0]]).toDouble()[0]  # we know Continuous Color only works with numeric attributes
        if (maxValue - minValue) <> 0:
          red = int ( maxRed * ( value - minValue ) / ( maxValue - minValue ) + minRed * ( maxValue - value ) / ( maxValue - minValue ) )
          green = int ( maxGreen * ( value - minValue ) / ( maxValue - minValue ) + minGreen * ( maxValue - value ) / ( maxValue - minValue ) )
          blue =  int ( maxBlue * ( value - minValue ) / ( maxValue - minValue ) + minBlue * ( maxValue - value ) / ( maxValue - minValue ) )
        else:
          red = minRed
          green = minGreen
          blue = minBlue
        newFillColor = QColor(red, green, blue)
        symbol.setFillColor(newFillColor)
        if renderer.drawPolygonOutline():
          # always black
          color = QColor(0,0,0)
          symbol.setColor(color)
        else:
          symbol.setColor(newFillColor)
        return symbol
      # else loop over symbols to find the current symbol for this feature
      # value can be string or numbers...
      value = (feature.attributeMap()[renderer.classificationAttributes()[0]]).toString()
      for symbol in renderer.symbols():
        lower = symbol.lowerValue()
        upper = symbol.upperValue()
        #print "lower: %s upper: %s value: %s notlower %s, notupper %s, value==lower %s, value=upper %s, str(value)[0].isdigit() %s" % (lower, upper, value, (not lower), (not upper), (value == lower), (value == upper), str(value)[0].isdigit())
        if not lower and not upper:
            # 'default value' given for default in Unique Value
            default = symbol
        # Unique Value symbols have the value in both upper and lower value (if values are string!)
        elif (value == lower and value == upper):
          return symbol
        # Unique Value symbols for numbers do not have an upper
        elif str(value)[0].isdigit() and not upper and float(value) == float(symbol.lowerValue()):
          return symbol
        # Graduated Classifications have lower AND uppervalues AND values are always numbers
        elif str(value)[0].isdigit() and upper and lower and (float(value) >= float(symbol.lowerValue()) and float(value) <= float(symbol.upperValue())):
          #print "Graduated Classification:  %s between %s and %s " % (value, symbol.lowerValue(), symbol.upperValue())
          return symbol
        #else:
        #  print "NEXT..."
      #print "RETURNING DEFAULT!!"
      return default

  def line2svg(self, feature, line, currentExtent):
    #print "calling line2svg..."
    linesvg = []
    svg = u''
    if self.svgType == SVG_TYPE_PATH:
      svg += '<path d="M '
    else:  # SVG_TYPE_SHAPE
      svg += '<polyline points="'
    lastPixel=[0,0]
    insideExtent = False
    coordCount = 0
    for point in line:
      if self.extentAsPoly.contains(point) or not self.featuresInMapcanvasOnly:
        insideExtent = True
      pixpoint =  self.w2p(point.x(), point.y(), self.iface.mapCanvas().mapUnitsPerPixel(), currentExtent.xMinimum(), currentExtent.yMaximum())
      #print pixpoint
      if lastPixel<>pixpoint:
        coordCount = coordCount +1
        if self.svgType==SVG_TYPE_PATH and coordCount>1:
          svg += 'L '
        svg += (str(pixpoint[0]) + ',' + str(pixpoint[1]) + ' ')
        lastPixel = pixpoint
    # if at least ONE pixel of this ring is in current view extent, return the area-string, otherwise return an empty string
    if not insideExtent:
      #print "RING FULLY OUTSIDE EXTENT: %s " % ring
      None
    else:
      # check if there are more then 2 coords: very small polygons on current map can have coordinates
      # which if rounded to pixels all come to the same pixel, resulting in just ONE x,y coordinate
      # we skip these
      if coordCount < 2:
        #print "Line contains just one pixel coordinate pair: skipping"
        None
      else:
        svg += '"/>\n'
        linesvg.append(svg)
    return linesvg

  # SHAPE-svg
  #  <polygon stroke="rgb(0,0,0)" fill="rgb(234,102,228)" stroke-width="1" points="439,238 445,230 ... 439,238"/>
  #     or
  #  <polygon points="439,238 445,230 ... 439,238"/>
  # PATH-svg
  #  <g stroke="rgb(0,0,0)" fill="rgb(234,102,228)" stroke-width="1" ><path d="M 439 238 L 445 220 ... L 439 238" /> </g>
  def polygon2svg(self, feature, polygon, currentExtent):
    #print "calling polygon2svg..."
    polygonsvg = ['']
    for ring in polygon:
      svg = ''
      if self.svgType == SVG_TYPE_PATH:
        svg += '<path d="M '
      else:  # SVG_TYPE_SHAPE
        svg = '<polygon points="'
      lastPixel=[0,0]
      insideExtent = False
      coordCount = 0
      for point in ring:
          if self.extentAsPoly.contains(point) or not self.featuresInMapcanvasOnly:
              insideExtent = True
          pixpoint =  self.w2p(point.x(), point.y(), self.iface.mapCanvas().mapUnitsPerPixel(), currentExtent.xMinimum(), currentExtent.yMaximum())
          if lastPixel<>pixpoint:
            coordCount = coordCount +1
            if self.svgType==SVG_TYPE_PATH and coordCount>1:
              svg += 'L '
            svg += (str(pixpoint[0]) + ',' + str(pixpoint[1]) + ' ')
            lastPixel = pixpoint
      # if at least ONE pixel of this ring is in current view extent, return the area-string, otherwise return an empty string
      if not insideExtent:
          #print "RING FULLY OUTSIDE EXTENT: %s " % ring
          None
      else:
          # check if there are more then 2 coords: very small polygons on current map can have coordinates
          # which if rounded to pixels all come to the same pixel, resulting in just ONE x,y coordinate
          # we skip these
          if coordCount < 2:
              #print "Ring contains just one pixel coordinate pair: skipping"
              None
          else:
              svg += '" />\n'
              polygonsvg.append(svg)
    return polygonsvg

  # NOT WORKING ????
  # pixpoint = m2p.transform(point.x(), point.y())
  # print m2p.transform(point.x(), point.y())
  # so for now: a custom 'world2pixel' method
  def w2p(self, x, y, mupp, minx, maxy):
    pixX = (x - minx)/mupp
    pixY = (y - maxy)/mupp
    return [int(pixX), int(-pixY)]
예제 #4
0
class SimpleSvg:

    MSG_BOX_TITLE = "QGIS SimpleSvg Plugin "

    def __init__(self, iface):
        # Save reference to the QGIS interface
        self.iface = iface
        self.svgFilename = QSettings().value('/simplesvg/lastfile', '')
        self.svgType = SVG_TYPE_PATH
        self.strokeLineJoin = 'round'  # miter, round, bevel
        # normal usage: current scale, only the features which touch current mapcanvas
        # if setting this false, ALL features will be taken from the dataprovider
        # and rendered as vectors, NOTE: not working for raster layers !
        self.featuresInMapcanvasOnly = True

    def initGui(self):
        # Create action that will start plugin configuration
        self.action = QAction(QIcon(":/plugins/simplesvg/icon.png"), \
                "Save as SVG", self.iface.mainWindow())
        # connect the action to the run method
        QObject.connect(self.action, SIGNAL("activated()"), self.run)

        # Add toolbar button and menu item
        self.iface.addToolBarIcon(self.action)
        self.dlg = SimpleSvgDialog(self.iface)
        self.dlg.setFilePath(self.svgFilename)
        QObject.connect(self.dlg, SIGNAL("showHelp()"), self.showHelp)
        QObject.connect(self.dlg, SIGNAL("accepted()"), self.writeToFile)
        QObject.connect(self.dlg, SIGNAL("cbFeaturesInMapcanvasOnlyChanged"),
                        self.setFeaturesInMapcanvasOnly)

        # about
        self.aboutAction = QAction(QIcon(":/plugins/simplesvg/help.png"), \
                              "About", self.iface.mainWindow())
        self.aboutAction.setWhatsThis("SimpleSvg Plugin About")
        QObject.connect(self.aboutAction, SIGNAL("activated()"), self.about)
        # help
        self.helpAction = QAction(QIcon(":/plugins/simplesvg/help.png"), \
                              "Help", self.iface.mainWindow())
        self.helpAction.setWhatsThis("SimpleSvg Plugin Help")
        QObject.connect(self.helpAction, SIGNAL("activated()"), self.showHelp)
        if hasattr(self.iface, "addPluginToWebMenu"):
            self.iface.addPluginToWebMenu("&Save as SVG", self.action)
            self.iface.addPluginToWebMenu("&Save as SVG", self.aboutAction)
            self.iface.addPluginToWebMenu("&Save as SVG", self.helpAction)
        else:
            self.iface.addPluginToMenu("&Save as SVG", self.action)
            self.iface.addPluginToMenu("&Save as SVG", self.aboutAction)
            self.iface.addPluginToMenu("&Save as SVG", self.helpAction)

    def setFeaturesInMapcanvasOnly(self, checked):
        if not checked:
            QMessageBox.information(
                self.dlg, "Warning",
                "Be carefull: unchecking this, means QGIS is going to fetch ALL objects from your data.\nHandle with care for big datasets."
            )
        self.featuresInMapcanvasOnly = checked

    def showHelp(self):
        docFile = os.path.join(os.path.dirname(__file__), "docs", "index.html")
        QDesktopServices.openUrl(QUrl("file:" + docFile))

    def writeToFile(self):
        self.svgFilename = self.dlg.getFilePath()
        # save this filename in settings for later
        QSettings().setValue('/simplesvg/lastfile', self.svgFilename)
        output = self.writeSVG()
        file = open(self.svgFilename, "w")
        #print output
        for line in output:
            #print '%s - %s' % (type(line),line)
            file.write(line.encode('utf-8'))
        file.close()
        QMessageBox.information(self.iface.mainWindow(), \
                "SimpleSvg Plugin", "Finished writing to svg")

    def about(self):
        try:
            infoString = QString(
                "Written by Richard Duivenvoorde\nEmail - [email protected]\n")
            infoString = infoString.append(
                "Company - http://www.webmapper.net\n")
            infoString = infoString.append(
                "Source: http://github.com/rduivenvoorde/simplesvg/")
        except NameError:
            infoString = "Written by Richard Duivenvoorde\nEmail - [email protected]\n"
            infoString += "Company - http://www.webmapper.net\n"
            infoString += "Source: http://github.com/rduivenvoorde/simplesvg/"
        QMessageBox.information(self.iface.mainWindow(), \
                  "SimpleSvg Plugin About", infoString)

    def unload(self):
        # Remove the plugin menu item and icon
        if hasattr(self.iface, "addPluginToWebMenu"):
            self.iface.removePluginWebMenu("&Save as SVG", self.action)
            self.iface.removePluginWebMenu("&Save as SVG", self.helpAction)
            self.iface.removePluginWebMenu("&Save as SVG", self.aboutAction)
        else:
            self.iface.removePluginMenu("&Save as SVG", self.action)
            self.iface.removePluginMenu("&Save as SVG", self.helpAction)
            self.iface.removePluginMenu("&Save as SVG", self.aboutAction)

        self.iface.removeToolBarIcon(self.action)

        QObject.disconnect(self.aboutAction, SIGNAL("activated()"), self.about)
        QObject.disconnect(self.helpAction, SIGNAL("activated()"),
                           self.showHelp)
        QObject.disconnect(self.action, SIGNAL("activated()"), self.run)
        QObject.disconnect(self.dlg, SIGNAL("accepted()"), self.writeToFile)

    # run method that performs all the real work
    def run(self):
        self.dlg.show()

    def writeSVG(self):
        # determine extent for later use (only write geoms that are at least partially contained)
        self.currentExtent = self.iface.mapCanvas().extent()
        w = self.iface.mapCanvas().size().width()
        h = self.iface.mapCanvas().size().height()
        # keep the current extent as a Geometry to be able to do some 'contains' tests later
        self.extentAsPoly = QgsGeometry()
        self.extentAsPoly = QgsGeometry.fromRect(self.currentExtent)

        svg = [u'<?xml version="1.0" standalone="no"?>\n']
        svg.append(
            u'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n'
        )
        svg.append(
            u'<svg xmlns="http://www.w3.org/2000/svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox = "0 0 '
            + str(w) + ' ' + str(h) + '" version = "1.1">\n')
        svg.append(u'<!-- svg generated using QGIS www.qgis.org -->\n')

        # for all visible layers, from bottom to top (-1)
        for i in range(self.iface.mapCanvas().layerCount() - 1, -1, -1):
            layer = self.iface.mapCanvas().layer(i)
            if layer.type() == 0:  # vector
                if self.isRendererV2(layer):
                    #QMessageBox.information(self.iface.mainWindow(), "Warning", "New Symbology layer found for layer '"+layer.name()+"'\n\nThe plugin cannot handle layer(s) which use 'New Symbology' yet.\n\nThis layer will be ignored in export.\n\nPlease change symbology of these layer(s) to 'Old Symbology' if you want this layer in svg.")
                    #pass
                    svg.extend(self.writeVectorLayer(layer, False))
                else:  # old symbology
                    svg.extend(self.writeVectorLayer(layer, False))
            elif layer.type() == 1:  # raster
                svg.extend(self.writeRaster(layer))
            # layers like OpenLayers/OpenStreetmap/Google are plugin layer: write as raster for now
            elif layer.type() == 2:  # plugin layer
                svg.extend(self.writeRaster(layer))

        # now layers with labels
        for i in range(self.iface.mapCanvas().layerCount() - 1, -1, -1):
            layer = self.iface.mapCanvas().layer(i)
            if layer.type() == 0:  # vector
                lblSettings = QgsPalLayerSettings()
                lblSettings.readFromLayer(layer)
            #TODO: fix this if layer.type()==0 and layer.hasLabelsEnabled(): # only vectors have labels
            if layer.type(
            ) == 0 and lblSettings.enabled:  # only vectors have labels
                svg.extend(self.writeVectorLayer(layer, True))

        # qgis extent, usable for clipping in Inkscape
        svg.extend(self.writeExtent())
        svg.append(u'</svg>')
        return svg

    def isRendererV2(self, layer):
        return (layer.type() == 0 and hasattr(layer, 'isUsingRendererV2')
                and layer.isUsingRendererV2()) or (
                    layer.type() == 0
                    and not hasattr(layer, 'isUsingRendererV2') and
                    ('rendererV2' in dir(layer)))

    def isRendererV2SIP2(self, layer):
        return (layer.type() == 0 and not hasattr(layer, 'isUsingRendererV2')
                and ('rendererV2' in dir(layer)))

    def writeVectorLayer(self, layer, labels=False):
        # in case of 'on the fly projection'
        # AND
        # different crs's for mapCanvas/project and layer we have to reproject stuff
        if hasattr(self.iface.mapCanvas().mapRenderer(), "destinationSrs"):
            # QGIS < 2.0
            destinationCrs = self.iface.mapCanvas().mapRenderer(
            ).destinationSrs()
            layerCrs = layer.srs()
        else:
            destinationCrs = self.iface.mapCanvas().mapRenderer(
            ).destinationCrs()
            layerCrs = layer.crs()
        if self.featuresInMapcanvasOnly:
            mapCanvasExtent = self.iface.mapCanvas().extent()
        else:
            mapCanvasExtent = layer.extent()
        #print 'destination crs: %s:' % destinationCrs.toProj4()
        #print 'layer crs:       %s:' % layerCrs.toProj4()
        doCrsTransform = False
        if not destinationCrs == layerCrs:
            # we have to transform the mapCanvasExtent to the data/layer Crs to be able
            # to retrieve the features from the data provider
            # but ONLY if we are working with on the fly projection
            # (because in that case we just 'fly' to the raw coordinates from data)
            if self.iface.mapCanvas().hasCrsTransformEnabled():
                # only if we have 'on te fly transformation' enabled
                #    AND the mapCanvasExtent is the real mapcanvas extent (note: if we
                # are going to write ALL features, then mapCanvasExtent is actually the layer extent)
                if self.featuresInMapcanvasOnly:
                    crsTransform = QgsCoordinateTransform(
                        destinationCrs, layerCrs)
                    mapCanvasExtent = crsTransform.transformBoundingBox(
                        mapCanvasExtent)
                # we have to have a transformer to do the transformation of the geometries
                # to the mapcanvas crs ourselves:
                crsTransform = QgsCoordinateTransform(layerCrs, destinationCrs)
                doCrsTransform = True

        lblSettings = QgsPalLayerSettings()
        lblSettings.readFromLayer(layer)

        # select features within current extent,
        #   with  ALL attributes, WITHIN currentExtent, WITH geom, AND using Intersect instead of bbox
        # we are going to group all features by their symbol so in svg we can group them in a <g> tag with the symbol style
        if self.isRendererV2(layer):
            if hasattr(layer, 'isUsingRendererV2'):
                # For QGis 1.8 API, new symbology
                provider = layer.dataProvider()
                provider.select(provider.attributeIndexes(), mapCanvasExtent,
                                True, True)
            else:
                # For QGis 2.0 cleaned-up API
                provider = layer.getFeatures(
                    QgsFeatureRequest().setFilterRect(mapCanvasExtent))
            renderer = layer.rendererV2()
            if str(renderer.type()) not in ("singleSymbol",
                                            "categorizedSymbol",
                                            "graduatedSymbol"):
                QMessageBox.information(
                    self.iface.mainWindow(), "Warning",
                    "New Symbology layer found for layer '" + layer.name() +
                    "'\n\nThis layer uses a Renderer/Style which cannot be used with this plugin.\n\nThis layer will be ignored in export."
                )
                return ""
        else:
            # For QGis <= 1.8 API, old symbology
            provider = layer.dataProvider()
            provider.select(provider.attributeIndexes(), mapCanvasExtent, True,
                            True)
            renderer = layer.renderer()
        symbols = renderer.symbols()
        symbolFeatureMap = dict.fromkeys(symbols, [])
        id = self.sanitizeStr(unicode(layer.name()).lower())
        if labels:
            id = id + '_labels'
        svg = [
            u'<g id="' + id + '" inkscape:groupmode="layer" inkscape:label="' +
            id + '">\n'
        ]
        # start of layer g-element
        # now iterate through each feature and group by feature
        f = QgsFeature()
        feature = None
        #print "1 symbols holds %s symbols" % len(symbols)
        while provider.nextFeature(f):
            feature = QgsFeature(f)
            geom = feature.geometry()
            if hasattr(layer, "srs"):
                # QGIS < 2.0
                layerCrs = layer.srs()
            else:
                layerCrs = layer.crs()

            if doCrsTransform:
                if hasattr(geom, "transform"):
                    geom.transform(crsTransform)
                else:
                    QMessageBox.warning(self.iface.mainWindow(
                    ), self.MSG_BOX_TITLE, (
                        "Cannot crs-transform geometry in your QGIS version ...\n"
                        "Only QGIS version 1.5 and above can transform geometries on the fly\n"
                        "As a workaround, you can try to save the layer in the destination crs (eg as shapefile) and reload that layer...\n"
                    ), QMessageBox.Ok, QMessageBox.Ok)
                    break

            symbol = self.symbolForFeature(layer, feature)
            #print "feature: %s  symbol: %s rgb: %s %s %s" % (feature, symbol, symbol.color().red(), symbol.color().green(), symbol.color().blue())
            # Continous Color does NOT have all symbols, but ONLY start and end color
            # that's why we do some extra stuff here...
            # ONLY needed for Old Symbology (which have 'name()' and not 'type()')
            if hasattr(renderer,
                       'name') and renderer.name() == "Continuous Color":
                symbols.append(symbol)
                if symbol in symbolFeatureMap:
                    symbolFeatureMap[symbol] = [feature]
                else:
                    symbolFeatureMap.update({symbol: [feature]})
            else:
                if not symbol in symbolFeatureMap or len(
                        symbolFeatureMap[symbol]) == 0:
                    symbolFeatureMap[symbol] = [feature]
                else:
                    symbolFeatureMap[symbol].append(feature)
        # now iterate over symbols IF there are any features in this view from this layer
        if feature != None:
            id = id + '_'
            i = 0
            #print "2 symbols holds %s symbols" % len(symbols)
            for symbol in symbols:
                if self.isRendererV2(layer):
                    sym = self.symbolV2(feature, symbol)
                else:
                    sym = self.symbol(feature, symbol)
                # start of symbol g-element, holds colors and stroke etc
                if not labels:
                    fill = ''
                    if sym.has_key('fill'):
                        fill = 'fill="' + sym['fill'] + '"'
                    svg.append(u'<g stroke="' + sym['stroke'] + '" ' + fill +
                               ' stroke-linejoin="' + self.strokeLineJoin +
                               '" stroke-width="' + sym['stroke-width'] +
                               '">\n')
                else:
                    # TODO fix this
                    if False:
                        lc = layer.label().labelAttributes().color()
                        lblColor = u'rgb(%s,%s,%s)' % (lc.red(), lc.green(),
                                                       lc.blue())
                    else:  # labels all black for now...
                        lblColor = u'rgb(0,0,0)'
                    svg.append(u'<g stroke="none" fill="' + lblColor + '">\n')
                for feature in symbolFeatureMap[symbol]:
                    i = i + 1
                    # labeltxt is used both for the real labels, AND for the inkscape-label attributes of g and txt elements
                    # TODO fix this
                    if lblSettings.enabled:
                        labeltxt = self.sanitizeStr(
                            feature[lblSettings.fieldName])
                    else:
                        #labeltxt = self.sanitizeStr(layer.label().fieldValue(0, feature)) # only first field for now.
                        #labeltxt = self.sanitizeStr(unicode(feature.fields().field(0)))
                        labeltxt = self.sanitizeStr('')
                    if not labels:
                        svg.extend(
                            self.writeFeature(feature, id + str(i), labeltxt))
                    if labels:
                        geom = feature.geometry().centroid()
                        # centroid-method returns a NON-transformed centroid
                        if doCrsTransform:
                            if hasattr(geom, "transform"):
                                geom.transform(crsTransform)
                            else:
                                QMessageBox.warning(self.iface.mainWindow(
                                ), self.MSG_BOX_TITLE, (
                                    "Cannot crs-transform geometry in your QGIS version ...\n"
                                    "Only QGIS version 1.5 and above can transform geometries on the fly\n"
                                    "As a workaround, you can try to save the layer in the destination crs (eg as shapefile) and reload that layer...\n"
                                ), QMessageBox.Ok, QMessageBox.Ok)
                                break
                        svg.extend(
                            self.label2svg(
                                geom.asPoint(), id + str(i),
                                self.symbolForFeature(layer, feature),
                                labeltxt))
                svg.append(u'</g>\n')
                # end of symbol
        svg.append(u'</g>\n')
        # end of layer
        return svg

    def symbol(self, feature, symbol):
        sym = {}
        sc = symbol.color()
        sym['stroke'] = u'rgb(%s,%s,%s)' % (sc.red(), sc.green(), sc.blue())
        # fill color: only non line features have fill color, lines have 'none'
        geom = feature.geometry()
        if geom.wkbType() in (QGis.WKBLineString, QGis.WKBLineString25D,
                              QGis.WKBMultiLineString,
                              QGis.WKBMultiLineString25D):
            sym['fill'] = u'none'
        else:
            f = symbol.fillColor()
            sym['fill'] = u'rgb(%s,%s,%s)' % (f.red(), f.green(), f.blue())
        # pen: in QT pen can be 0
        if symbol.pen().width() < 1:
            sym['stroke-width'] = u'0.5'
        else:
            sym['stroke-width'] = unicode(symbol.pen().width())
        return sym

    def symbolV2(self, feature, symbol):
        #print '##### symbol: %s, symbollayercount: %s' % (symbol, symbol.symbolLayerCount())
        sym = {}
        if symbol.symbolLayerCount() > 1:
            QMessageBox.information(
                self.iface.mainWindow(), "Warning", "Layer '" + layer.name() +
                "' uses New Symbology, and styles with more the one Symbol Layer, only the first one will be use."
            )
        sl = symbol.symbolLayer(0)
        slprops = sl.properties()
        #print("symbollayer properties: %s" % slprops)
        # region/polgyons have: color_border / style_border / offset / style / color / width_border
        #  {PyQt4.QtCore.QString(u'color_border'): PyQt4.QtCore.QString(u'0,0,0,255'), PyQt4.QtCore.QString(u'style_border'): PyQt4.QtCore.QString(u'solid'), PyQt4.QtCore.QString(u'offset'): PyQt4.QtCore.QString(u'0,0'), PyQt4.QtCore.QString(u'style'): PyQt4.QtCore.QString(u'solid'), PyQt4.QtCore.QString(u'color'): PyQt4.QtCore.QString(u'0,0,255,255'), PyQt4.QtCore.QString(u'width_border'): PyQt4.QtCore.QString(u'0.26')}
        # markers/points have : color_border / offset / size / color / name / angle:
        #  {PyQt4.QtCore.QString(u'color_border'): PyQt4.QtCore.QString(u'0,0,0,255'), PyQt4.QtCore.QString(u'offset'): PyQt4.QtCore.QString(u'0,0'), PyQt4.QtCore.QString(u'size'): PyQt4.QtCore.QString(u'2'), PyQt4.QtCore.QString(u'color'): PyQt4.QtCore.QString(u'255,0,0,255'), PyQt4.QtCore.QString(u'name'): PyQt4.QtCore.QString(u'circle'), PyQt4.QtCore.QString(u'angle'): PyQt4.QtCore.QString(u'0')}
        # lines have          : color / offset / penstyle / width / use_custom_dash / joinstyle / customdash / capstyle:
        #  {PyQt4.QtCore.QString(u'color'): PyQt4.QtCore.QString(u'255,255,0,255'), PyQt4.QtCore.QString(u'offset'): PyQt4.QtCore.QString(u'0'), PyQt4.QtCore.QString(u'penstyle'): PyQt4.QtCore.QString(u'solid'), PyQt4.QtCore.QString(u'width'): PyQt4.QtCore.QString(u'0.5'), PyQt4.QtCore.QString(u'use_custom_dash'): PyQt4.QtCore.QString(u'0'), PyQt4.QtCore.QString(u'joinstyle'): PyQt4.QtCore.QString(u'bevel'), PyQt4.QtCore.QString(u'customdash'): PyQt4.QtCore.QString(u'5;2'), PyQt4.QtCore.QString(u'capstyle'): PyQt4.QtCore.QString(u'square')}
        try:
            strokekey = QString(u'line_color')
            strokekey2 = QString(u'outline_color')
            colorkey = QString(u'color')
            stylekey = QString(u'style')
            width_borderkey = QString(u'width_border')
            widthkey = QString(u'width')
        except NameError:
            strokekey = u'line_color'
            strokekey2 = u'outline_color'
            colorkey = u'color'
            stylekey = u'style'
            width_borderkey = u'width_border'
            widthkey = u'width'
        if slprops.has_key(strokekey):
            stroke = unicode(slprops[strokekey])
            sym['stroke'] = u'rgb(%s)' % (stroke[:stroke.rfind(',')])
        elif slprops.has_key(strokekey2):
            stroke = unicode(slprops[strokekey2])
            sym['stroke'] = u'rgb(%s)' % (stroke[:stroke.rfind(',')])
        else:
            sym['stroke'] = u'none'
        # fill color: only non line features have fill color, lines have 'none'
        geom = feature.geometry()
        if slprops.has_key(colorkey):
            fill = unicode(slprops[colorkey])
            if geom.wkbType() in (QGis.WKBLineString, QGis.WKBLineString25D,
                                  QGis.WKBMultiLineString,
                                  QGis.WKBMultiLineString25D):
                sym['stroke'] = u'rgb(%s)' % (fill[:fill.rfind(',')])
            # points have fill and stroke
            sym['fill'] = u'rgb(%s)' % (fill[:fill.rfind(',')])
        # if feature is line OR when there is no brush: set fill to none
        if geom.wkbType() in (QGis.WKBLineString, QGis.WKBLineString25D, QGis.WKBMultiLineString, QGis.WKBMultiLineString25D) \
                or (slprops.has_key(stylekey) and slprops[stylekey] == 'no'):
            sym['fill'] = u'none'
        # pen: in QT pen can be 0
        if slprops.has_key(width_borderkey):
            sym['stroke-width'] = unicode(slprops[width_borderkey])
        elif slprops.has_key(widthkey):
            sym['stroke-width'] = unicode(slprops[widthkey])
        else:
            sym['stroke-width'] = u'0.40'
        #print sym
        return sym

    def writeExtent(self):
        svg = [
            u'<!-- QGIS extent for clipping, eg in Inkscape -->\n<g id="qgisviewbox" inkscape:groupmode="layer" inkscape:label="qgisviewbox" stroke="rgb(255,0,0)" stroke-width="1" fill="none" >\n'
        ]
        for ring in self.extentAsPoly.asPolygon():
            svg.append(u'<path d="M ')
            first = True
            for point in ring:
                pixpoint = self.w2p(point.x(), point.y(),
                                    self.iface.mapCanvas().mapUnitsPerPixel(),
                                    self.currentExtent.xMinimum(),
                                    self.currentExtent.yMaximum())
                if not first:
                    svg.append(u'L ')
                svg.append(
                    (unicode(pixpoint[0]) + ',' + unicode(pixpoint[1]) + ' '))
                first = False
            svg.append(u'" />\n')
        svg.append(u'</g>')
        return svg

    def writeRaster(self, layer):
        # hide all layers except 'layer' and save as png image in current directory
        # TODO? maybe inline it in svg?
        # save visibility of layers
        visibleList = self.iface.mapCanvas().layers()
        legend = self.iface.legendInterface()
        # set all layers invisible EXCEPT layer
        for lyr in visibleList:
            if lyr != layer:
                legend.setLayerVisible(lyr, False)
        lyrName = unicode(layer.name())
        imgName = lyrName + '.png'
        try:
            imgPath = self.svgFilename[:self.svgFilename.rfind('/') + 1]
        except NameError:
            imgPath = self.svgFilename[:self.svgFilename.rfind('/') + 1]
        # save image next to svg but put it in Image tag only the local filename
        self.iface.mapCanvas().saveAsImage(imgPath + imgName)
        # <image y="-7.7685061" x="27.115078" id="image3890" xlink:href="nl.png" />
        svg = [
            u'<g id="' + lyrName +
            '" inkscape:groupmode="layer" inkscape:label="' + lyrName + '">\n'
        ]
        #svg.append('<image y="0" x="0" xlink:href="'+imgPath+imgName+'" />')
        svg.append(u'<image y="0" x="0" xlink:href="' + imgName + '" />')
        svg.append(u'</g>')  # end of raster layer
        # now set earlier visible layers back to visible
        for lyr in visibleList:
            legend.setLayerVisible(lyr, True)
        return svg

    def label2svg(self, point, fid, symbol, labelTxt):
        # <g> <text x="262.08704" y="523.79077">abc</text> </g>
        #point = feature.geometry().centroid().asPoint()
        xy = self.w2p(point.x(), point.y(),
                      self.iface.mapCanvas().mapUnitsPerPixel(),
                      self.currentExtent.xMinimum(),
                      self.currentExtent.yMaximum())
        inkscapeLbl = ''
        if len(labelTxt) > 0:
            inkscapeLbl = 'inkscape:label="' + unicode(labelTxt + '_lbl') + '"'
        svg = [
            u'<text id="' + fid + '" x="' + unicode(xy[0]) + '" y="' +
            unicode(xy[1]) + '" ' + inkscapeLbl + '>' + unicode(labelTxt) +
            '</text>\n'
        ]
        return svg

    def sanitizeStr(self, string):
        # TODO: find the right way to do this
        return unicode(string).replace(' ', '_').replace('/', '_').replace(
            ',', '_').replace('.', '_')

    def writeFeature(self, feature, fid, labelTxt):
        svg = []
        # <g>-element set's style attributes
        inkscapeLbl = ''
        if len(labelTxt) > 0:
            inkscapeLbl = 'inkscape:label="' + unicode(labelTxt) + '"'
        svg.append(u'<g id="' + fid + '" ' + inkscapeLbl + '>\n')
        geom = feature.geometry()
        currentExtent = self.currentExtent
        # https://qgis.org/api/2.18/classQGis.html#a8da456870e1caec209d8ba7502cceff7
        #print(geom.wkbType(), QGis.WKBPoint, QGis.WKBPoint25D)
        if geom.wkbType() in (QGis.WKBPoint, QGis.WKBPoint25D):  # 1 = WKBPoint
            point = geom.asPoint()
            svg.extend(self.point2svg(point, currentExtent))
        if geom.wkbType() in (QGis.WKBMultiPoint, QGis.WKBMultiPoint25D):
            multipoint = geom.asMultiPoint()
            for point in multipoint:
                svg.extend(self.point2svg(point, currentExtent))
        if geom.wkbType() in (QGis.WKBPolygon,
                              QGis.WKBPolygon25D):  # 3 = WKBTYPE.WKBPolygon:
            polygon = geom.asPolygon()  # returns a list
            svg.extend(self.polygon2svg(feature, polygon, currentExtent))
        if geom.wkbType() in (
                QGis.WKBMultiPolygon,
                QGis.WKBMultiPolygon25D):  # 6 = WKBTYPE.WKBMultiPolygon:
            multipolygon = geom.asMultiPolygon()  # returns a list
            for polygon in multipolygon:
                svg.extend(self.polygon2svg(feature, polygon, currentExtent))
        if geom.wkbType() in (
                QGis.WKBLineString,
                QGis.WKBLineString25D):  # 6 = WKBTYPE.WKBLineString:
            line = geom.asPolyline()  # returns a list of points
            svg.extend(self.line2svg(feature, line, currentExtent))
        if geom.wkbType() in (
                QGis.WKBMultiLineString,
                QGis.WKBMultiLineString25D):  # 6 = WKBTYPE.WKBLineString:
            multiline = geom.asMultiPolyline()  # returns a list of points
            for line in multiline:
                svg.extend(self.line2svg(feature, line, currentExtent))
        svg.append(u'</g>\n')
        return svg

    def point2svg(self, point, currentExtent):
        #point = feature.geometry().asPoint()
        xy = self.w2p(point.x(), point.y(),
                      self.iface.mapCanvas().mapUnitsPerPixel(),
                      self.currentExtent.xMinimum(),
                      self.currentExtent.yMaximum())
        #print(point, xy, point.x(), point.y(), self.iface.mapCanvas().mapUnitsPerPixel(), self.currentExtent.xMinimum(), self.currentExtent.yMaximum())
        # TODO take current extent into account
        svg = [
            '<circle cx="' + unicode(xy[0]) + '" cy="' + unicode(xy[1]) +
            '" r="5" />'
        ]
        return svg

    def symbolForFeature(self, layer, feature):
        if self.isRendererV2(layer):
            return layer.rendererV2().symbolForFeature(feature)
        else:
            # symbolForFeatures seems not to work for Old Symbology?? Do it ourselves:
            # OLD symbolisation:
            #   Graduated Symbol: every symbol has BOTH upper and lower bound/value
            #   Unique Value: every symbol has BOTH upper and lower value
            #   Continues Color: HAS lower(==value) but NO upper value, BUT has just two symbols: MIN and MAX color, see http://doc.qgis.org/head/qgscontinuouscolorrenderer_8cpp-source.html
            #   Single Simbol: just one symbol, return it
            renderer = layer.renderer()
            #print "renderer.name(): %s" % renderer.name()
            default = None
            if renderer.name(
            ) == "Single Symbol":  # there is just one symbol: return it
                return renderer.symbols()[0]
            if renderer.name() == "Continuous Color":
                #pass  # already done, should not come here !!
                minSymbol = renderer.symbols()[0]
                minValue = (minSymbol.lowerValue()).toDouble(
                )[0]  # we know Continuous Color only works with numeric attributes
                minRed = minSymbol.fillColor().red()
                minGreen = minSymbol.fillColor().green()
                minBlue = minSymbol.fillColor().blue()
                maxSymbol = renderer.symbols()[1]
                maxValue = (maxSymbol.lowerValue()).toDouble(
                )[0]  # we know Continuous Color only works with numeric attributes
                maxRed = maxSymbol.fillColor().red()
                maxGreen = maxSymbol.fillColor().green()
                maxBlue = maxSymbol.fillColor().blue()
                # create new symbol and set RGB according to calculation in http://doc.qgis.org/head/qgscontinuouscolorrenderer_8cpp-source.html
                symbol = QgsSymbol(minSymbol)  # copy
                value = (feature.attributeMap(
                )[renderer.classificationAttributes()[0]]).toDouble(
                )[0]  # we know Continuous Color only works with numeric attributes
                if (maxValue - minValue) <> 0:
                    red = int(maxRed * (value - minValue) /
                              (maxValue - minValue) + minRed *
                              (maxValue - value) / (maxValue - minValue))
                    green = int(maxGreen * (value - minValue) /
                                (maxValue - minValue) + minGreen *
                                (maxValue - value) / (maxValue - minValue))
                    blue = int(maxBlue * (value - minValue) /
                               (maxValue - minValue) + minBlue *
                               (maxValue - value) / (maxValue - minValue))
                else:
                    red = minRed
                    green = minGreen
                    blue = minBlue
                newFillColor = QColor(red, green, blue)
                symbol.setFillColor(newFillColor)
                if renderer.drawPolygonOutline():
                    # always black
                    color = QColor(0, 0, 0)
                    symbol.setColor(color)
                else:
                    symbol.setColor(newFillColor)
                return symbol
            # else loop over symbols to find the current symbol for this feature
            # value can be string or numbers...
            value = (feature.attributeMap()[
                renderer.classificationAttributes()[0]]).toString()
            for symbol in renderer.symbols():
                lower = symbol.lowerValue()
                upper = symbol.upperValue()
                #print "lower: %s upper: %s value: %s notlower %s, notupper %s, value==lower %s, value=upper %s, str(value)[0].isdigit() %s" % (lower, upper, value, (not lower), (not upper), (value == lower), (value == upper), str(value)[0].isdigit())
                if not lower and not upper:
                    # 'default value' given for default in Unique Value
                    default = symbol
                # Unique Value symbols have the value in both upper and lower value (if values are string!)
                elif (value == lower and value == upper):
                    return symbol
                # Unique Value symbols for numbers do not have an upper
                elif str(value)[0].isdigit() and not upper and float(
                        value) == float(symbol.lowerValue()):
                    return symbol
                # Graduated Classifications have lower AND uppervalues AND values are always numbers
                elif str(value)[0].isdigit() and upper and lower and (
                        float(value) >= float(symbol.lowerValue())
                        and float(value) <= float(symbol.upperValue())):
                    #print "Graduated Classification:  %s between %s and %s " % (value, symbol.lowerValue(), symbol.upperValue())
                    return symbol
                #else:
                #  print "NEXT..."
            #print "RETURNING DEFAULT!!"
            return default

    def line2svg(self, feature, line, currentExtent):
        #print("calling line2svg...")
        linesvg = []
        svg = u''
        if self.svgType == SVG_TYPE_PATH:
            svg += '<path d="M '
        else:  # SVG_TYPE_SHAPE
            svg += '<polyline points="'
        lastPixel = [0, 0]
        insideExtent = False
        coordCount = 0
        for point in line:
            if self.extentAsPoly.contains(
                    point) or not self.featuresInMapcanvasOnly:
                insideExtent = True
            pixpoint = self.w2p(point.x(), point.y(),
                                self.iface.mapCanvas().mapUnitsPerPixel(),
                                currentExtent.xMinimum(),
                                currentExtent.yMaximum())
            #print(pixpoint)
            if lastPixel <> pixpoint:
                coordCount = coordCount + 1
                if self.svgType == SVG_TYPE_PATH and coordCount > 1:
                    svg += 'L '
                svg += (str(pixpoint[0]) + ',' + str(pixpoint[1]) + ' ')
                lastPixel = pixpoint
        # if at least ONE pixel of this ring is in current view extent, return the area-string, otherwise return an empty string
        if not insideExtent:
            #print("SKIPPING: Ring fully outside extent...?")
            pass
        else:
            # check if there are more then 2 coords: very small polygons on current map can have coordinates
            # which if rounded to pixels all come to the same pixel, resulting in just ONE x,y coordinate
            # we skip these
            if coordCount < 2:
                #print("SKIPPING: Line contains just one pixel coordinate pair")
                pass
            else:
                svg += '"/>\n'
                linesvg.append(svg)
                #print(linesvg)
        return linesvg

    # SHAPE-svg
    #  <polygon stroke="rgb(0,0,0)" fill="rgb(234,102,228)" stroke-width="1" points="439,238 445,230 ... 439,238"/>
    #     or
    #  <polygon points="439,238 445,230 ... 439,238"/>
    # PATH-svg
    #  <g stroke="rgb(0,0,0)" fill="rgb(234,102,228)" stroke-width="1" ><path d="M 439 238 L 445 220 ... L 439 238" /> </g>
    def polygon2svg(self, feature, polygon, currentExtent):
        #print "calling polygon2svg..."
        polygonsvg = ['']
        for ring in polygon:
            svg = ''
            if self.svgType == SVG_TYPE_PATH:
                svg += '<path d="M '
            else:  # SVG_TYPE_SHAPE
                svg = '<polygon points="'
            lastPixel = [0, 0]
            insideExtent = False
            coordCount = 0
            for point in ring:
                if self.extentAsPoly.contains(
                        point) or not self.featuresInMapcanvasOnly:
                    insideExtent = True
                pixpoint = self.w2p(point.x(), point.y(),
                                    self.iface.mapCanvas().mapUnitsPerPixel(),
                                    currentExtent.xMinimum(),
                                    currentExtent.yMaximum())
                if lastPixel <> pixpoint:
                    coordCount = coordCount + 1
                    if self.svgType == SVG_TYPE_PATH and coordCount > 1:
                        svg += 'L '
                    svg += (str(pixpoint[0]) + ',' + str(pixpoint[1]) + ' ')
                    lastPixel = pixpoint
            # if at least ONE pixel of this ring is in current view extent, return the area-string, otherwise return an empty string
            if not insideExtent:
                #print "RING FULLY OUTSIDE EXTENT: %s " % ring
                None
            else:
                # check if there are more then 2 coords: very small polygons on current map can have coordinates
                # which if rounded to pixels all come to the same pixel, resulting in just ONE x,y coordinate
                # we skip these
                if coordCount < 2:
                    #print "Ring contains just one pixel coordinate pair: skipping"
                    None
                else:
                    svg += '" />\n'
                    polygonsvg.append(svg)
        return polygonsvg

    # NOT WORKING ????
    # pixpoint = m2p.transform(point.x(), point.y())
    # print m2p.transform(point.x(), point.y())
    # so for now: a custom 'world2pixel' method
    def w2p(self, x, y, mupp, minx, maxy):
        pixX = (x - minx) / mupp
        pixY = (y - maxy) / mupp
        return [int(pixX), int(-pixY)]