/[thuban]/trunk/thuban/Extensions/svgexport/svgmapwriter.py
ViewVC logotype

Diff of /trunk/thuban/Extensions/svgexport/svgmapwriter.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2081 by bh, Thu Feb 19 13:38:27 2004 UTC revision 2082 by bh, Fri Feb 20 14:33:22 2004 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003, 2004 by Intevation GmbH
2  # Authors:  # Authors:
3  #     Markus Rechtien <[email protected]>  #     Markus Rechtien <[email protected]>
4  #  #
5  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
6  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
7    
 __version__ = "$Revision$"  
 # $Source$  
 # $Id$  
   
8    
9  """  """
10  Classes needed to write a session in SVG format  Classes needed to write a session in SVG format
11  """  """
12    
13    # For compatibility with python 2.2
 # For compatibility with python > 2.3  
14  from __future__ import generators  from __future__ import generators
15    
16    
17    __version__ = "$Revision$"
18    # $Source$
19    # $Id$
20    
21    
22  # Regular expressions used with Fontnames  # Regular expressions used with Fontnames
23  import re  import re
24  # Combining strings  # Combining strings
25  from string import join  from string import join
26  # We need to determine some object types  # We need to determine some object types
27  from types import ListType, TupleType  from types import ListType
28  # VirtualDC extends XMLWriter  # VirtualDC extends XMLWriter
29  from Thuban.Model.xmlwriter import XMLWriter, escape  from Thuban.Model.xmlwriter import XMLWriter, escape
30  # Color related classes from the model of thuban  # Color related classes from the model of thuban
31  from Thuban.Model.color import Transparent, Color, Black    from Thuban.Model.color import Transparent, Black
32  # The SVGRenderer is subclass of BaseRenderer  # The SVGRenderer is subclass of BaseRenderer
33  from Thuban.UI.baserenderer import BaseRenderer  from Thuban.UI.baserenderer import BaseRenderer
34    
# Line 45  svg_caps = {'':'', 'butt':'butt', 'round Line 47  svg_caps = {'':'', 'butt':'butt', 'round
47  # Some pseudo classes to be compatible with the Baserenderer-class.  # Some pseudo classes to be compatible with the Baserenderer-class.
48  #  #
49  class Point:  class Point:
50      '''A simple Point class.'''      """A simple Point class."""
51      def __init__(self, xp=0, yp=0):      def __init__(self, xp=0, yp=0):
52          '''Init the point object.'''          """Init the point object."""
53          self.x = xp          self.x = xp
54          self.y = yp          self.y = yp
55    
56  class Trafo:  class Trafo:
57      '''Class for tranformation properties transfer.'''      """Class for tranformation properties transfer."""
58      def __init__(self):      def __init__(self):
59          '''Initialize the class.'''          """Initialize the class."""
60          self.trafos = []          self.trafos = []
61            
62      def Append(self, type, coeffs):      def Append(self, type, coeffs):
63          '''Append a transformation to the list.'''          """Append a transformation to the list."""
64          self.trafos.append((type, coeffs))          self.trafos.append((type, coeffs))
65            
66      def Count(self):      def Count(self):
67          '''Get the number of transformations in list.'''          """Get the number of transformations in list."""
68          return len(self.trafos)          return len(self.trafos)
69            
70      def Pop(self):      def Pop(self):
71          '''Pop and return a transformation from the end of the list.'''          """Pop and return a transformation from the end of the list."""
72          if len(self.trafos) > 0:          if len(self.trafos) > 0:
73              return self.trafos.pop()              return self.trafos.pop()
74          else: return None          else: return None
75    
76  class Pattern:  class Pattern:
77      '''Pattern object '''      """Pattern object """
78      def __init__(self, solid=1):      def __init__(self, solid=1):
79          '''Init the Pattern object.'''          """Init the Pattern object."""
80          self.solid = solid          self.solid = solid
81    
82  class Pen:  class Pen:
83      '''Pen object for property transfer.'''      """Pen object for property transfer."""
84      def __init__(self, pcolor = Black, pwidth = 1, pdashes = None):      def __init__(self, pcolor = Black, pwidth = 1, pdashes = None):
85          self.color = pcolor          self.color = pcolor
86          self.width = pwidth          self.width = pwidth
# Line 87  class Pen: Line 89  class Pen:
89          self.cap = 'round'          self.cap = 'round'
90            
91      def GetColor(self):      def GetColor(self):
92          '''Return the pen's color.'''          """Return the pen's color."""
93          return self.color          return self.color
94    
95      def GetWidth(self):      def GetWidth(self):
96          '''Return the pen's width.'''          """Return the pen's width."""
97          return self.width          return self.width
98    
99      def GetJoin(self):      def GetJoin(self):
100          '''Return the pen's join type.'''          """Return the pen's join type."""
101          return self.join          return self.join
102            
103      def GetCap(self):      def GetCap(self):
104          '''Return the pen's cap type.'''          """Return the pen's cap type."""
105          return self.cap          return self.cap
106            
107      def GetDashes(self):      def GetDashes(self):
108          '''Return the pen's dashes.'''          """Return the pen's dashes."""
109          if self.dashes is None or self.dashes is SOLID:          if self.dashes is None or self.dashes is SOLID:
110              return []              return []
111          else: return self.dashes          else: return self.dashes
112    
113  class Brush:  class Brush:
114      '''Brush property class.'''      """Brush property class."""
115      def __init__(self, bfill=Black, bpattern=None):      def __init__(self, bfill=Black, bpattern=None):
116          '''Init the brush with the given values.'''          """Init the brush with the given values."""
117          self.fill = bfill          self.fill = bfill
118          self.pattern = bpattern          self.pattern = bpattern
119            
120      def GetColor(self):      def GetColor(self):
121          '''Return the brush color.'''          """Return the brush color."""
122          return self.fill          return self.fill
123            
124      def GetPattern(self):      def GetPattern(self):
125          '''Return the Brush pattern object.'''          """Return the Brush pattern object."""
126          return self.pattern          return self.pattern
127    
128  class Font:  class Font:
129      '''Font class that accts as property object.'''      """Font class that accts as property object."""
130      def __init__(self, ffamily='Helvetica', fsize=12):      def __init__(self, ffamily='Helvetica', fsize=12):
131          '''Init the font with the given values.'''          """Init the font with the given values."""
132          self.family = ffamily          self.family = ffamily
133          self.size = fsize          self.size = fsize
134            
135      def GetFaceName(self):      def GetFaceName(self):
136          '''Return the fontfamily the font belongs to.'''          """Return the fontfamily the font belongs to."""
137          return self.family          return self.family
138            
139      def GetPointSize(self):      def GetPointSize(self):
140          '''Return the size of the font in points.'''          """Return the size of the font in points."""
141          return self.size          return self.size
142    
143  # Instantiate an empty pen.  # Instantiate an empty pen.
# Line 156  class SVGRenderer(BaseRenderer): Line 158  class SVGRenderer(BaseRenderer):
158      """      """
159      def __init__(self, dc, map, scale, offset, region,      def __init__(self, dc, map, scale, offset, region,
160                   resolution = 1.0, honor_visibility = 1):                   resolution = 1.0, honor_visibility = 1):
161          '''Init SVGRenderer and call superclass init.'''          """Init SVGRenderer and call superclass init."""
162          BaseRenderer.__init__(self, dc, map, scale, offset, region,          BaseRenderer.__init__(self, dc, map, scale, offset, region,
163                  resolution, honor_visibility)                  resolution, honor_visibility)
164          #          #
165          self.factor = (abs(region[2]) + abs(region[3])) / (2.0 * 1000.0)          self.factor = (abs(region[2]) + abs(region[3])) / (2.0 * 1000.0)
166                    
167      def make_point(self, x, y):      def make_point(self, x, y):
168          '''Return a Point object from two values.'''          """Return a Point object from two values."""
169          return Point(x, y)          return Point(x, y)
170            
171      def label_font(self):      def label_font(self):
# Line 171  class SVGRenderer(BaseRenderer): Line 173  class SVGRenderer(BaseRenderer):
173          return Font()          return Font()
174    
175      def tools_for_property(self, prop):      def tools_for_property(self, prop):
176          '''Return a pen/brush tuple build from a property object.'''          """Return a pen/brush tuple build from a property object."""
177          fill = prop.GetFill()          fill = prop.GetFill()
178          if fill is Transparent:          if fill is Transparent:
179              brush = TRANSPARENT_BRUSH              brush = TRANSPARENT_BRUSH
# Line 296  class SVGRenderer(BaseRenderer): Line 298  class SVGRenderer(BaseRenderer):
298          dc.EndGroup()          dc.EndGroup()
299            
300      def draw_raster_layer(self, layer):      def draw_raster_layer(self, layer):
301          '''Draw the raster layer'''          """Draw the raster layer"""
302          # For now we cannot draw raster layers onto our VirtualDC          # For now we cannot draw raster layers onto our VirtualDC
303          pass          pass
304            
# Line 306  class SVGRenderer(BaseRenderer): Line 308  class SVGRenderer(BaseRenderer):
308          pass          pass
309            
310      def RenderMap(self, selected_layer, selected_shapes):      def RenderMap(self, selected_layer, selected_shapes):
311          '''Overriden to avoid automatic rendering of legend,          """Overriden to avoid automatic rendering of legend,
312          scalbar and frame.          scalbar and frame.
313          '''          """
314          dc = self.dc          dc = self.dc
315          self.selected_layer = selected_layer          self.selected_layer = selected_layer
316          self.selected_shapes = selected_shapes          self.selected_shapes = selected_shapes
# Line 328  class SVGRenderer(BaseRenderer): Line 330  class SVGRenderer(BaseRenderer):
330            
331    
332  class VirtualDC(XMLWriter):  class VirtualDC(XMLWriter):
333      '''This class imitates a DC and writes SVG instead.      """This class imitates a DC and writes SVG instead.
334            
335      All shapes and graphic objects will be turned into      All shapes and graphic objects will be turned into
336      SVG elements and will be written into a file.      SVG elements and will be written into a file.
337      Any properties, such as stroke width or stroke color,      Any properties, such as stroke width or stroke color,
338      will be written together with the SVG elementents.      will be written together with the SVG elementents.
339      '''      """
340      def __init__(self, file, dim=(0,0), units=''):      def __init__(self, file, dim=(0,0), units=''):
341          '''Setup some variables and objects for property collection.'''          """Setup some variables and objects for property collection."""
342          XMLWriter.__init__(self)          XMLWriter.__init__(self)
343          self.dim = dim          self.dim = dim
344          self.units = units          self.units = units
# Line 352  class VirtualDC(XMLWriter): Line 354  class VirtualDC(XMLWriter):
354          self.write(file)          self.write(file)
355            
356      def write_indent(self, str):      def write_indent(self, str):
357          '''Write a string to the file with the current indention level.          """Write a string to the file with the current indention level.
358          '''          """
359          from Thuban.Model.xmlwriter import TAB          from Thuban.Model.xmlwriter import TAB
360          self.file.write("%s%s" % (TAB*self.indent_level, str))          self.file.write("%s%s" % (TAB*self.indent_level, str))
361            
362      def AddMeta(self, key, val):      def AddMeta(self, key, val):
363          '''Append some metadata to the array that will be          """Append some metadata to the array that will be
364          written with the next svg-element          written with the next svg-element
365          '''          """
366          if key is '' or val is '':          if key is '' or val is '':
367              return              return
368          self.meta[key] = val          self.meta[key] = val
369            
370      def SetMeta(self, pairs, flush_after=1):      def SetMeta(self, pairs, flush_after=1):
371          '''Delete old meta informations and set the new ones.'''          """Delete old meta informations and set the new ones."""
372          self.meta = {}          self.meta = {}
373          self.flush_meta = flush_after          self.flush_meta = flush_after
374          for key, val in pairs.items():          for key, val in pairs.items():
375              self.AddMeta(key, val)              self.AddMeta(key, val)
376            
377      def FlushMeta(self):      def FlushMeta(self):
378          '''Drop collected metadata.'''          """Drop collected metadata."""
379          self.meta = {}          self.meta = {}
380    
381      def BeginGroup(self, **args):      def BeginGroup(self, **args):
382          '''Begin a group of elements.          """Begin a group of elements.
383                    
384          Possible arguments:          Possible arguments:
385              meta        A list of key, value metadata pairs              meta        A list of key, value metadata pairs
386              style       A list of key, value style attributes              style       A list of key, value style attributes
387              clipid      The ID of a clipPath definition to be              clipid      The ID of a clipPath definition to be
388                          applied to this group                          applied to this group
389          '''          """
390          self.FlushMeta()          self.FlushMeta()
391          # adding meta data          # adding meta data
392          if args.has_key('meta'):          if args.has_key('meta'):
# Line 409  class VirtualDC(XMLWriter): Line 411  class VirtualDC(XMLWriter):
411          self.indent_level += 1          self.indent_level += 1
412            
413      def parse_trafo(self, trafo):      def parse_trafo(self, trafo):
414          '''Examine a trafo object for asigned transformations details.'''          """Examine a trafo object for asigned transformations details."""
415          if not trafo:          if not trafo:
416              return ''              return ''
417          retval = ''          retval = ''
# Line 422  class VirtualDC(XMLWriter): Line 424  class VirtualDC(XMLWriter):
424          return retval          return retval
425    
426      def EndGroup(self):      def EndGroup(self):
427          '''End a group of elements'''          """End a group of elements"""
428          self.indent_level -= 1          self.indent_level -= 1
429          self.write_indent('</g>\n')          self.write_indent('</g>\n')
430          self.FlushMeta()          self.FlushMeta()
431    
432      def BeginExport(self):      def BeginExport(self):
433          '''Start the export process and write basic document          """Start the export process and write basic document
434          informations to the file.          informations to the file.
435          '''          """
436          self.write_indent('<?xml version="1.0" encoding="ISO-8859-1" '          self.write_indent('<?xml version="1.0" encoding="ISO-8859-1" '
437              'standalone="yes"?>\n')              'standalone="yes"?>\n')
438          width, height = self.dim          width, height = self.dim
# Line 438  class VirtualDC(XMLWriter): Line 440  class VirtualDC(XMLWriter):
440          self.indent_level += 1          self.indent_level += 1
441            
442      def EndExport(self):      def EndExport(self):
443          '''End the export process with closing the SVG tag and close          """End the export process with closing the SVG tag and close
444          the file accessor'''          the file accessor"""
445          self.indent_level -= 1          self.indent_level -= 1
446          self.write_indent('</svg>\n')          self.write_indent('</svg>\n')
447          self.close()          self.close()
448            
449      def Close(self):      def Close(self):
450          '''Close the file.'''          """Close the file."""
451          self.close()          self.close()
452            
453      def BeginDrawing(self):      def BeginDrawing(self):
454          '''Dummy function to work with the Thuban renderers.'''          """Dummy function to work with the Thuban renderers."""
455          pass          pass
456                    
457      def EndDrawing(self):      def EndDrawing(self):
458          '''Dummy function to work with the Thuban renderers.'''          """Dummy function to work with the Thuban renderers."""
459          pass          pass
460            
461      def GetSizeTuple(self):      def GetSizeTuple(self):
462          '''Return the dimension of this virtual canvas.'''          """Return the dimension of this virtual canvas."""
463          return self.dim          return self.dim
464            
465      def GetTextExtent(self, text):      def GetTextExtent(self, text):
466          '''Return the dimension of the given text.'''          """Return the dimension of the given text."""
467          # FIXME: find something more appropriate          # FIXME: find something more appropriate
468          try:          try:
469              if self.font:              if self.font:
# Line 472  class VirtualDC(XMLWriter): Line 474  class VirtualDC(XMLWriter):
474              return (12,len(text) * 10)              return (12,len(text) * 10)
475            
476      def SetID(self, id):      def SetID(self, id):
477          '''Set the ID stored by the svg elements.'''          """Set the ID stored by the svg elements."""
478          self.id = id          self.id = id
479    
480      def SetBaseID(self, id):      def SetBaseID(self, id):
481          '''Set the ID stored by the svg elements.'''          """Set the ID stored by the svg elements."""
482          self.baseid = id          self.baseid = id
483                    
484      def SetFont(self, font):      def SetFont(self, font):
485          '''Set the fontproperties to use with text elements.'''          """Set the fontproperties to use with text elements."""
486          if font is not None:          if font is not None:
487              fontname = font.GetFaceName()              fontname = font.GetFaceName()
488              size = font.GetPointSize()              size = font.GetPointSize()
# Line 496  class VirtualDC(XMLWriter): Line 498  class VirtualDC(XMLWriter):
498              else: self.font["font-size"] = None              else: self.font["font-size"] = None
499            
500      def SetPen(self, pen):      def SetPen(self, pen):
501          '''Set the style of the pen used to draw graphics.'''          """Set the style of the pen used to draw graphics."""
502          if pen is TRANSPARENT_PEN:          if pen is TRANSPARENT_PEN:
503              self.pen = {}              self.pen = {}
504          else:          else:
# Line 507  class VirtualDC(XMLWriter): Line 509  class VirtualDC(XMLWriter):
509              self.pen["stroke-linecap"] = svg_caps[pen.GetCap()]              self.pen["stroke-linecap"] = svg_caps[pen.GetCap()]
510            
511      def SetBrush(self, brush):      def SetBrush(self, brush):
512          '''Set the fill properties.'''          """Set the fill properties."""
513          if brush is TRANSPARENT_BRUSH:          if brush is TRANSPARENT_BRUSH:
514              self.brush['fill'] = 'none'              self.brush['fill'] = 'none'
515          elif brush.GetPattern() is SOLID:          elif brush.GetPattern() is SOLID:
# Line 516  class VirtualDC(XMLWriter): Line 518  class VirtualDC(XMLWriter):
518              pass              pass
519            
520      def SetTextForeground(self, color):      def SetTextForeground(self, color):
521          '''Set the color of the text foreground.'''          """Set the color of the text foreground."""
522          self.font['fill'] = color.hex()          self.font['fill'] = color.hex()
523                    
524      def make_style(self, line=0, fill=0, font=0):      def make_style(self, line=0, fill=0, font=0):
525          '''Build the style attribute including desired properties          """Build the style attribute including desired properties
526          such as fill, forground, stroke, etc.'''          such as fill, forground, stroke, etc."""
527          result = []          result = []
528          # little helper function          # little helper function
529          def append(pairs):          def append(pairs):
# Line 542  class VirtualDC(XMLWriter): Line 544  class VirtualDC(XMLWriter):
544              return ''              return ''
545            
546      def make_meta(self, meta=None):      def make_meta(self, meta=None):
547          '''Build the meta attribute.'''          """Build the meta attribute."""
548          result = []          result = []
549          if not meta:          if not meta:
550              meta = self.meta              meta = self.meta
# Line 556  class VirtualDC(XMLWriter): Line 558  class VirtualDC(XMLWriter):
558          return 'meta="%s"' % (join(result, '; '))          return 'meta="%s"' % (join(result, '; '))
559            
560      def make_id(self):      def make_id(self):
561          '''Get the ID for the next object - if current ID is valid.'''          """Get the ID for the next object - if current ID is valid."""
562          if self.id < 0:          if self.id < 0:
563              return ''              return ''
564          else: return 'id="%s%s"' % (self.baseid, self.id)          else: return 'id="%s%s"' % (self.baseid, self.id)
565    
566      def DrawEllipse(self, x, y, dx, dy):      def DrawEllipse(self, x, y, dx, dy):
567          '''Draw an ellipse.'''          """Draw an ellipse."""
568          elips = '<ellipse cx="%s" cy="%s" rx="%s" ry="%s" %s %s %s/>\n'          elips = '<ellipse cx="%s" cy="%s" rx="%s" ry="%s" %s %s %s/>\n'
569          self.write_indent(elips % (x, y, dx, dy, self.make_id(),          self.write_indent(elips % (x, y, dx, dy, self.make_id(),
570                  self.make_style(1,1,0), self.make_meta()) )                  self.make_style(1,1,0), self.make_meta()) )
571            
572      def DrawCircle(self, x, y, radius):      def DrawCircle(self, x, y, radius):
573          '''Draw a circle onto the virtual dc.'''          """Draw a circle onto the virtual dc."""
574          self.write_indent('<circle cx="%s" cy="%s" r="%s" %s %s %s/>\n' %          self.write_indent('<circle cx="%s" cy="%s" r="%s" %s %s %s/>\n' %
575                  (x, y, radius, self.make_id(), self.make_style(1,1,0),                  (x, y, radius, self.make_id(), self.make_style(1,1,0),
576                  self.make_meta()) )                  self.make_meta()) )
577            
578      def DrawRectangle(self, x, y, width, height):      def DrawRectangle(self, x, y, width, height):
579          '''Draw a rectangle with the given parameters.'''          """Draw a rectangle with the given parameters."""
580          rect = '<rect x="%s" y="%s" width="%s" height="%s" %s %s %s/>\n'          rect = '<rect x="%s" y="%s" width="%s" height="%s" %s %s %s/>\n'
581          self.write_indent(rect %  ( x, y, width, height, self.make_id(),          self.write_indent(rect %  ( x, y, width, height, self.make_id(),
582              self.make_style(1,1,0), self.make_meta()) )              self.make_style(1,1,0), self.make_meta()) )
583    
584      def DrawText(self, text, x, y):      def DrawText(self, text, x, y):
585          '''Draw Text at the given position.'''          """Draw Text at the given position."""
586          beginText = '<text x="%s" y="%s" %s %s %s>'          beginText = '<text x="%s" y="%s" %s %s %s>'
587          self.write_indent(beginText %  ( x, y, self.make_id(),          self.write_indent(beginText %  ( x, y, self.make_id(),
588              self.make_style(0,0,1), self.make_meta()) )              self.make_style(0,0,1), self.make_meta()) )
# Line 588  class VirtualDC(XMLWriter): Line 590  class VirtualDC(XMLWriter):
590          self.file.write('</text>\n')          self.file.write('</text>\n')
591            
592      def DrawLines(self, points):      def DrawLines(self, points):
593          '''Draw some points into a Buffer that will be          """Draw some points into a Buffer that will be
594          written before the next object.          written before the next object.
595          '''          """
596          self.DrawPolygon(points,0)          self.DrawPolygon(points,0)
597            
598      def DrawPolygon(self, polygon, closed=1):      def DrawPolygon(self, polygon, closed=1):
599          '''Draw a polygon onto the virtual dc.'''          """Draw a polygon onto the virtual dc."""
600          self.write_indent('<path %s ' % (self.make_style(1,1,0)))          self.write_indent('<path %s ' % (self.make_style(1,1,0)))
601          data = []          data = []
602          i = 0          i = 0
# Line 612  class VirtualDC(XMLWriter): Line 614  class VirtualDC(XMLWriter):
614              self.make_meta(), join(data, '') ) )              self.make_meta(), join(data, '') ) )
615            
616      def DrawSpline(self, points, closed=0):      def DrawSpline(self, points, closed=0):
617          '''Draw a spline object.          """Draw a spline object.
618          '''          """
619          self.DrawPolygon(points, 0)          self.DrawPolygon(points, 0)
620          print "TODO: DrawSpline(..)"          print "TODO: DrawSpline(..)"
621          return # TODO: Implement          return # TODO: Implement
622    
623      def BeginClipPath(self, id):      def BeginClipPath(self, id):
624          '''Build a clipping region to draw in.'''          """Build a clipping region to draw in."""
625          self.write_indent('<clipPath id="%s">\n' % id)          self.write_indent('<clipPath id="%s">\n' % id)
626          self.indent_level += 1          self.indent_level += 1
627            
628      def EndClipPath(self):      def EndClipPath(self):
629          '''End a clip path.'''          """End a clip path."""
630          self.indent_level -= 1          self.indent_level -= 1
631          self.write_indent("</clipPath>\n")          self.write_indent("</clipPath>\n")

Legend:
Removed from v.2081  
changed lines
  Added in v.2082

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26