GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
instructions.py
Go to the documentation of this file.
1 """!
2 @package psmap.instructions
3 
4 @brief Map feature objects
5 
6 Classes:
7  - dialogs::Instruction
8  - dialogs::InstructionObject
9  - dialogs::InitMap
10  - dialogs::MapFrame
11  - dialogs::PageSetup
12  - dialogs::Mapinfo
13  - dialogs::Text
14  - dialogs::Image
15  - dialogs::NorthArrow
16  - dialogs::Point
17  - dialogs::Line
18  - dialogs::Rectangle
19  - dialogs::Scalebar
20  - dialogs::RasterLegend
21  - dialogs::VectorLegend
22  - dialogs::Raster
23  - dialogs::Vector
24  - dialogs::VProperties
25 
26 (C) 2011-2012 by Anna Kratochvilova, and the GRASS Development Team
27 
28 This program is free software under the GNU General Public License
29 (>=v2). Read the file COPYING that comes with GRASS for details.
30 
31 @author Anna Kratochvilova <kratochanna gmail.com> (bachelor's project)
32 @author Martin Landa <landa.martin gmail.com> (mentor)
33 """
34 
35 import os
36 import string
37 from math import ceil
38 from time import strftime, localtime
39 
40 import wx
41 import grass.script as grass
42 
43 from core.gcmd import RunCommand, GError, GMessage, GWarning
44 from core.utils import CmdToTuple, GetCmdString
45 from dbmgr.vinfo import VectorDBInfo
46 from psmap.utils import *
47 
49  """!Class which represents instruction file"""
50  def __init__(self, parent, objectsToDraw):
51 
52  self.parent = parent
53  self.objectsToDraw = objectsToDraw
54  #here are kept objects like mapinfo, rasterlegend, etc.
55  self.instruction = list()
56 
57  def __str__(self):
58  """!Returns text for instruction file"""
59  comment = "# timestamp: " + strftime("%Y-%m-%d %H:%M", localtime()) + '\n'
60  env = grass.gisenv()
61  comment += "# location: %s\n" % env['LOCATION_NAME']
62  comment += "# mapset: %s\n" % env['MAPSET']
63  comment += "# page orientation: %s\n" % self.FindInstructionByType('page')['Orientation']
64  border = ''
65  if not self.FindInstructionByType('map'):
66  border = 'border n\n'
67  text = [str(each) for each in self.instruction]
68  return comment + border + '\n'.join(text) + '\nend'
69 
70  def __getitem__(self, id):
71  for each in self.instruction:
72  if each.id == id:
73  return each
74  return None
75 
76  def __contains__(self, id):
77  """!Test if instruction is included"""
78  for each in self.instruction:
79  if each.id == id:
80  return True
81  return False
82 
83  def __delitem__(self, id):
84  """!Delete instruction"""
85  for each in self.instruction:
86  if each.id == id:
87  if each.type == 'map':
88  #must remove raster, vector layers too
89  vektor = self.FindInstructionByType('vector', list = True)
90  vProperties = self.FindInstructionByType('vProperties', list = True)
91  raster = self.FindInstructionByType('raster', list = True)
92  for item in vektor + vProperties + raster:
93  if item in self.instruction:
94  self.instruction.remove(item)
95 
96  self.instruction.remove(each)
97  if id in self.objectsToDraw:
98  self.objectsToDraw.remove(id)
99  return
100 
101  def AddInstruction(self, instruction):
102  """!Add instruction"""
103  # add to instructions
104  if instruction.type == 'map':
105  self.instruction.insert(0, instruction)
106  else:
107  self.instruction.append(instruction)
108  # add to drawable objects
109  if instruction.type not in ('page', 'raster', 'vector', 'vProperties', 'initMap'):
110  if instruction.type == 'map':
111  self.objectsToDraw.insert(0, instruction.id)
112  else:
113  self.objectsToDraw.append(instruction.id)
114 
115 
116  def FindInstructionByType(self, type, list = False):
117  """!Find instruction(s) with the given type"""
118  inst = []
119  for each in self.instruction:
120  if each.type == type:
121  inst.append(each)
122  if len(inst) == 1 and not list:
123  return inst[0]
124  return inst
125 
126  def Read(self, filename):
127  """!Reads instruction file and creates instruction objects"""
128  self.filename = filename
129  # open file
130  try:
131  file = open(filename, 'r')
132  except IOError:
133  GError(message = _("Unable to open file\n%s") % filename)
134  return
135  # first read file to get information about region and scaletype
136  isRegionComment = False
137  orientation = 'Portrait'
138  for line in file:
139  if '# g.region' in line:
140  self.SetRegion(regionInstruction = line)
141  isRegionComment = True
142  break
143  if '# page orientation' in line:
144  orientation = line.split(':')[-1].strip()
145 
146  if not isRegionComment:
147  self.SetRegion(regionInstruction = None)
148  # then run ps.map -b to get information for maploc
149  # compute scale and center
150  map = self.FindInstructionByType('map')
151  region = grass.region()
152  map['center'] = (region['n'] + region['s']) / 2, (region['w'] + region['e']) / 2
153  mapRect = GetMapBounds(self.filename, portrait = (orientation == 'Portrait'))
154  map['rect'] = mapRect
155  proj = projInfo()
156  toM = 1.0
157  if proj['units']:
158  toM = float(proj['meters'])
159  units = UnitConversion(self.parent)
160  w = units.convert(value = mapRect.Get()[2], fromUnit = 'inch', toUnit = 'meter') / toM
161  map['scale'] = w / abs((region['w'] - region['e']))
162 
163  SetResolution(dpi = 300, width = map['rect'].width, height = map['rect'].height)
164 
165  # read file again, now with information about map bounds
166  isBuffer = False
167  buffer = []
168  instruction = None
169  vectorMapNumber = 1
170  file.seek(0)
171  for line in file:
172  if not line.strip():
173  continue
174  line = line.strip()
175  if isBuffer:
176  buffer.append(line)
177  if 'end' in line:
178  isBuffer = False
179  kwargs = {}
180  if instruction == 'scalebar':
181  kwargs['scale'] = map['scale']
182  elif instruction in ('text', 'eps', 'point', 'line', 'rectangle'):
183  kwargs['mapInstruction'] = map
184  elif instruction in ('vpoints', 'vlines', 'vareas'):
185  kwargs['id'] = wx.NewId()
186  kwargs['vectorMapNumber'] = vectorMapNumber
187  vectorMapNumber += 1
188  elif instruction == 'paper':
189  kwargs['Orientation'] = orientation
190 
191  ok = self.SendToRead(instruction, buffer, **kwargs)
192  if not ok: return False
193  buffer = []
194  continue
195 
196  elif line.startswith('paper'):
197  instruction = 'paper'
198  isBuffer = True
199  buffer.append(line)
200 
201  elif line.startswith('border'):
202  if line.split()[1].lower() in ('n', 'no', 'none'):
203  ok = self.SendToRead('border', [line])
204  if not ok: return False
205  elif line.split()[1].lower() in ('y', 'yes'):
206  instruction = 'border'
207  isBuffer = True
208  buffer.append(line)
209 
210  elif line.startswith('scale '):
211  if isBuffer:
212  continue
213  ok = self.SendToRead('scale', line, isRegionComment = isRegionComment)
214  if not ok: return False
215 
216  elif line.startswith('maploc'):
217  ok = self.SendToRead(instruction = 'maploc', text = line)
218  if not ok: return False
219 
220  elif line.startswith('raster'):
221  ok = self.SendToRead(instruction = 'raster', text = line)
222  if not ok: return False
223 
224  elif line.startswith('mapinfo'):
225  instruction = 'mapinfo'
226  isBuffer = True
227  buffer.append(line)
228 
229 
230  elif line.startswith('scalebar'):
231  instruction = 'scalebar'
232  isBuffer = True
233  buffer.append(line)
234 
235  elif line.startswith('text'):
236  instruction = 'text'
237  isBuffer = True
238  buffer.append(line)
239 
240  elif line.startswith('eps'):
241  instruction = 'eps'
242  isBuffer = True
243  buffer.append(line)
244 
245  elif line.startswith('point'):
246  instruction = 'point'
247  isBuffer = True
248  buffer.append(line)
249 
250  elif line.startswith('line'):
251  instruction = 'line'
252  isBuffer = True
253  buffer.append(line)
254 
255  elif line.startswith('rectangle'):
256  instruction = 'rectangle'
257  isBuffer = True
258  buffer.append(line)
259 
260  elif line.startswith('colortable'):
261  if len(line.split()) == 2 and line.split()[1].lower() in ('n', 'no', 'none'):
262  break
263  instruction = 'colortable'
264  isBuffer = True
265  buffer.append(line)
266 
267  elif line.startswith('vlegend'):
268  instruction = 'vlegend'
269  isBuffer = True
270  buffer.append(line)
271 
272  elif line.startswith('vpoints'):
273  instruction = 'vpoints'
274  isBuffer = True
275  buffer.append(line)
276 
277  elif line.startswith('vlines'):
278  instruction = 'vlines'
279  isBuffer = True
280  buffer.append(line)
281 
282  elif line.startswith('vareas'):
283  instruction = 'vareas'
284  isBuffer = True
285  buffer.append(line)
286 
287 
288 
289  rasterLegend = self.FindInstructionByType('rasterLegend')
290  raster = self.FindInstructionByType('raster')
291  page = self.FindInstructionByType('page')
292  vector = self.FindInstructionByType('vector')
293  vectorLegend = self.FindInstructionByType('vectorLegend')
294  vectorMaps = self.FindInstructionByType('vProperties', list = True)
295 
296  # check (in case of scaletype 0) if map is drawn also
297  map['drawMap'] = False
298  if map['scaleType'] == 0:
299  mapForRegion = map['map']
300  if map['mapType'] == 'raster' and raster:
301  if mapForRegion == raster['raster']:
302  map['drawMap'] = True
303  elif map['mapType'] == 'vector' and vector:
304  for vmap in vector['list']:
305  if mapForRegion == vmap[0]:
306  map['drawMap'] = True
307 
308  # rasterLegend
309  if rasterLegend:
310  if rasterLegend['rasterDefault'] and raster:
311  rasterLegend['raster'] = raster['raster']
312  if not rasterLegend['discrete']:
313  rasterType = getRasterType(map = rasterLegend['raster'])
314  if rasterType == 'CELL':
315  rasterLegend['discrete'] = 'y'
316  else:
317  rasterLegend['discrete'] = 'n'
318 
319  #estimate size
320  height = rasterLegend.EstimateHeight(raster = rasterLegend['raster'], discrete = rasterLegend['discrete'],
321  fontsize = rasterLegend['fontsize'],
322  cols = rasterLegend['cols'],
323  height = rasterLegend['height'])
324  width = rasterLegend.EstimateWidth(raster = rasterLegend['raster'], discrete = rasterLegend['discrete'],
325  fontsize = rasterLegend['fontsize'],
326  cols = rasterLegend['cols'] ,
327  width = rasterLegend['width'],
328  paperInstr = page)
329  rasterLegend['rect'] = Rect2D(x = float(rasterLegend['where'][0]), y = float(rasterLegend['where'][1]),
330  width = width, height = height)
331 
332  # vectors, vlegend
333 
334  if vector:
335  for vmap in vectorMaps:
336  for i, each in enumerate(vector['list']):
337  if each[2] == vmap.id:
338 
339  vector['list'][i][4] = vmap['label']
340  vector['list'][i][3] = vmap['lpos']
341  if vectorLegend:
342  size = vectorLegend.EstimateSize(vectorInstr = vector, fontsize = vectorLegend['fontsize'],
343  width = vectorLegend['width'], cols = vectorLegend['cols'])
344  vectorLegend['rect'] = Rect2D(x = float(vectorLegend['where'][0]), y = float(vectorLegend['where'][1]),
345  width = size[0], height = size[1])
346 
347 
348  page = self.FindInstructionByType('page')
349  if not page:
350  page = PageSetup(wx.NewId())
351  self.AddInstruction(page)
352  else:
353  page['Orientation'] = orientation
354 
355 
356  #
357  return True
358 
359  def SendToRead(self, instruction, text, **kwargs):
360  psmapInstrDict = dict(paper = ['page'],
361  maploc = ['map'],
362  scale = ['map'],
363  border = ['map'],
364  raster = ['raster'],
365  mapinfo = ['mapinfo'],
366  scalebar = ['scalebar'],
367  text = ['text'],
368  eps = ['image', 'northArrow'],
369  point = ['point'],
370  line = ['line'],
371  rectangle = ['rectangle'],
372  vpoints = ['vector', 'vProperties'],
373  vlines = ['vector', 'vProperties'],
374  vareas = ['vector', 'vProperties'],
375  colortable = ['rasterLegend'],
376  vlegend = ['vectorLegend']
377  )
378 
379  myInstrDict = dict(page = PageSetup,
380  map = MapFrame,
381  raster = Raster,
382  mapinfo = Mapinfo,
383  scalebar = Scalebar,
384  text = Text,
385  image = Image,
386  northArrow = NorthArrow,
387  point = Point,
388  line = Line,
389  rectangle = Rectangle,
390  rasterLegend = RasterLegend,
391  vectorLegend = VectorLegend,
392  vector = Vector,
393  vProperties = VProperties
394  )
395 
396  myInstruction = psmapInstrDict[instruction]
397 
398  for i in myInstruction:
399  instr = self.FindInstructionByType(i)
400  if i in ('text', 'vProperties', 'image', 'northArrow', 'point', 'line', 'rectangle') or not instr:
401 
402  id = wx.NewId() #!vProperties expect subtype
403  if i == 'vProperties':
404  id = kwargs['id']
405  newInstr = myInstrDict[i](id, subType = instruction[1:])
406  elif i in ('image', 'northArrow'):
407  commentFound = False
408  for line in text:
409  if line.find("# north arrow") >= 0:
410  commentFound = True
411  if i == 'image' and commentFound or \
412  i == 'northArrow' and not commentFound:
413  continue
414  newInstr = myInstrDict[i](id, settings = self)
415  else:
416  newInstr = myInstrDict[i](id)
417  ok = newInstr.Read(instruction, text, **kwargs)
418  if ok:
419  self.AddInstruction(newInstr)
420  else:
421  return False
422 
423  else:
424  ok = instr.Read(instruction, text, **kwargs)
425 
426  if not ok:
427  return False
428  return True
429 
430  def SetRegion(self, regionInstruction):
431  """!Sets region from file comment or sets current region in case of no comment"""
432  map = MapFrame(wx.NewId())
433  self.AddInstruction(map)
434  if regionInstruction:
435  cmd = CmdToTuple(regionInstruction.strip('# ').split())
436 
437  # define scaleType
438  if len(cmd[1]) <= 3:
439  if 'rast' in cmd[1]:
440  map['scaleType'] = 0
441  map['mapType'] = 'raster'
442  map['map'] = cmd[1]['rast']
443  elif 'vect' in cmd[1]:
444  map['scaleType'] = 0
445  map['mapType'] = 'vector'
446  map['map'] = cmd[1]['vect']
447  elif 'region' in cmd[1]:
448  map['scaleType'] = 1
449  map['region'] = cmd[1]['region']
450 
451  else:
452  map['scaleType'] = 2
453  else:
454  map['scaleType'] = 2
455  grass.del_temp_region()
456  region = grass.region()
457  grass.use_temp_region()
458  cmd = ['g.region', region]
459  cmdString = GetCmdString(cmd).replace('g.region', '')
460  GMessage(_("Instruction file will be loaded with following region: %s\n") % cmdString)
461  try:
462  RunCommand(cmd[0], **cmd[1])
463 
464  except grass.ScriptError, e:
465  GError(_("Region cannot be set\n%s") % e)
466  return False
467 
468 
470  """!Abtract class representing single instruction"""
471  def __init__(self, id):
472  self.id = id
473 
474  # default values
475  self.defaultInstruction = dict()
476  # current values
478  # converting units
479  self.unitConv = UnitConversion()
480 
481  def __str__(self):
482  """!Returns particular part of text instruction"""
483  return ''
484 
485  def __getitem__(self, key):
486  for each in self.instruction.keys():
487  if each == key:
488  return self.instruction[key]
489  return None
490 
491  def __setitem__(self, key, value):
492  self.instruction[key] = value
493 
494  def GetInstruction(self):
495  """!Get current values"""
496  return self.instruction
497 
498  def SetInstruction(self, instruction):
499  """!Set default values"""
500  self.instruction = instruction
501 
502  def Read(self, instruction, text, **kwargs):
503  """!Read instruction and save them"""
504  pass
505 
506  def PercentToReal(self, e, n):
507  """!Converts text coordinates from percent of region to map coordinates"""
508  e, n = float(e.strip('%')), float(n.strip('%'))
509  region = grass.region()
510  N = region['s'] + (region['n'] - region['s']) / 100 * n
511  E = region['w'] + (region['e'] - region['w']) / 100 * e
512  return E, N
513 
515  """!Class representing virtual map"""
516  def __init__(self, id):
517  InstructionObject.__init__(self, id = id)
518  self.type = 'initMap'
519 
520  # default values
521  self.defaultInstruction = dict(rect = None, scale = None)
522  # current values
523  self.instruction = dict(self.defaultInstruction)
524 
525 
527  """!Class representing map (instructions maploc, scale, border)"""
528  def __init__(self, id):
529  InstructionObject.__init__(self, id = id)
530  self.type = 'map'
531  # default values
532  self.defaultInstruction = dict(map = None, mapType = None, drawMap = True, region = None,
533  rect = Rect2D(), scaleType = 0, scale = None, center = None,
534  resolution = 300, border = 'y', width = 1, color = '0:0:0')
535  # current values
536  self.instruction = dict(self.defaultInstruction)
537 
538  def __str__(self):
539  instr = ''
540  comment = ''
541 
542  #region settings
543  region = grass.region()
544  if self.instruction['scaleType'] == 0: #match map
545  map = self.instruction['map']
546  if self.instruction['mapType'] == 'raster':
547  comment = "# g.region rast=%s nsres=%s ewres=%s\n" % (map, region['nsres'], region['ewres'])
548  else:
549  comment = "# g.region vect=%s\n" % (map)
550  elif self.instruction['scaleType'] == 1:# saved region
551  region = self.instruction['region']
552  comment = "# g.region region=%s\n" % region
553  elif self.instruction['scaleType'] in (2, 3): #current region, fixed scale
554  comment = string.Template("# g.region n=$n s=$s e=$e w=$w rows=$rows cols=$cols \n").substitute(**region)
555 
556  instr += comment
557  instr += '\n'
558  # maploc
559  maplocInstruction = "maploc %.3f %.3f" % (self.instruction['rect'].x, self.instruction['rect'].y)
560  if self.instruction['scaleType'] != 3:
561  maplocInstruction += " %.3f %.3f"% (self.instruction['rect'].width, self.instruction['rect'].height)
562  instr += maplocInstruction
563  instr += '\n'
564 
565  # scale
566  if self.instruction['scaleType'] == 3: #fixed scale
567  scaleInstruction = "scale 1:%.0f" % (1/self.instruction['scale'])
568  instr += scaleInstruction
569  instr += '\n'
570  # border
571  borderInstruction = ''
572  if self.instruction['border'] == 'n':
573  borderInstruction = "border n"
574  else:
575  borderInstruction = "border y\n"
576  borderInstruction += string.Template(" width $width\n color $color\n").substitute(self.instruction)
577  borderInstruction += " end"
578  instr += borderInstruction
579  instr += '\n'
580 
581  return instr
582 
583  def Read(self, instruction, text, **kwargs):
584  """!Read instruction and save information"""
585  if 'isRegionComment' in kwargs:
586  isRegionComment = kwargs['isRegionComment']
587  instr = {}
588 
589  if instruction == 'border':
590  for line in text:
591  if line.startswith('end'):
592  break
593  try:
594  if line.split()[1].lower() in ('n', 'no', 'none'):
595  instr['border'] = 'n'
596  break
597  elif line.split()[1].lower() in ('y', 'yes'):
598  instr['border'] = 'y'
599  elif line.startswith('width'):
600  instr['width'] = line.split()[1]
601  elif line.startswith('color'):
602  instr['color'] = line.split()[1]
603  except IndexError:
604  GError(_("Failed to read instruction %s") % instruction)
605  return False
606 
607  elif instruction == 'scale':
608  try:
609  scaleText = text.strip('scale ').split(':')[1]
610  # when scale instruction given and region comment also, then scaletype is fixed scale
611  if not isRegionComment:
612  instr['scaleType'] = 2
613  else:
614  instr['scaleType'] = 3
615 
616  scale = 1/float(scaleText)
617  if abs(scale - self.instruction['scale']) > (0.01 * scale):
618  GWarning(_("Scale has changed, old value: %(old)s\nnew value: %(new)s") % \
619  { 'old' : scale, 'new' : self.instruction['scale'] })
620  except (ValueError, IndexError):
621  GError(_("Failed to read instruction %s.\nUse 1:25000 notation.") % instruction)
622  return False
623 
624  elif instruction == 'maploc':
625  maploc = text.strip('maploc ').split()
626  if len(maploc) >= 2:
627  if abs(self.instruction['rect'].Get()[0] - float(maploc[0])) > 0.5 or \
628  abs(self.instruction['rect'].Get()[1] - float(maploc[1])) > 0.5:
629  GWarning(_("Map frame position changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % \
630  { 'old1' : maploc[0], 'old2' : maploc[1],
631  'new1' : self.instruction['rect'].Get()[0], 'new2' : self.instruction['rect'].Get()[1] })
632 
633  #instr['rect'] = wx.Rect2D(float(maploc[0]), float(maploc[1]), self.instruction['rect'][2], self.instruction['rect'][3])
634  if len(maploc) == 4:
635  if abs(self.instruction['rect'].Get()[2] - float(maploc[2])) > 0.5 or \
636  abs(self.instruction['rect'].Get()[3] - float(maploc[3])) > 0.5:
637  GWarning(_("Map frame size changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % \
638  { 'old1' : maploc[2], 'old2' : maploc[3],
639  'new1' : self.instruction['rect'].Get()[2], 'new2' : self.instruction['rect'].Get()[3] })
640  #instr['rect'] = wx.Rect2D(*map(float, maploc))
641  self.instruction.update(instr)
642  return True
643 
645  """!Class representing page instruction"""
646  def __init__(self, id):
647  InstructionObject.__init__(self, id = id)
648  self.type = 'page'
649  # default values
650  self.defaultInstruction = dict(Units = 'inch', Format = 'a4', Orientation = 'Portrait',
651  Width = 8.268, Height = 11.693, Left = 0.5, Right = 0.5, Top = 1, Bottom = 1)
652  # current values
653  self.instruction = dict(self.defaultInstruction)
654 
655  def __str__(self):
656  if self.instruction['Format'] == 'custom':
657  instr = string.Template("paper\n width $Width\n height $Height\n").substitute(self.instruction)
658  else:
659  instr = string.Template("paper $Format\n").substitute(self.instruction)
660  instr += string.Template(" left $Left\n right $Right\n bottom $Bottom\n top $Top\n end").substitute(self.instruction)
661 
662  return instr
663 
664  def Read(self, instruction, text, **kwargs):
665  """!Read instruction and save information"""
666  instr = {}
667  self.cats = ['Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
668  self.subInstr = dict(zip(['width', 'height', 'left', 'right', 'top', 'bottom'], self.cats))
669 
670  if instruction == 'paper': # just for sure
671  for line in text:
672  if line.startswith('paper'):
673  if len(line.split()) > 1:
674  pformat = line.split()[1]
675  availableFormats = self._toDict(grass.read_command('ps.map', flags = 'p',
676  quiet = True))
677  # e.g. paper a3
678  try:
679  instr['Format'] = pformat
680  for key, value in availableFormats[pformat].iteritems():
681  instr[key] = float(value)
682  break
683  except KeyError:
684  GError(_("Failed to read instruction %(file)s.\nUnknown format %(for)s") % \
685  { 'file' : instruction, 'for' : format })
686  return False
687  else:
688  # paper
689  # width ...
690  instr['Format'] = 'custom'
691  # read subinstructions
692  elif instr['Format'] == 'custom' and not line.startswith('end'):
693  text = line.split()
694  try:
695  instr[self.subInstr[text[0]]] = float(text[1])
696  except (IndexError, KeyError):
697  GError(_("Failed to read instruction %s.") % instruction)
698  return False
699 
700  if 'Orientation' in kwargs and kwargs['Orientation'] == 'Landscape':
701  instr['Width'], instr['Height'] = instr['Height'], instr['Width']
702 
703  self.instruction.update(instr)
704  return True
705 
706  def _toDict(self, paperStr):
707  sizeDict = dict()
708 # cats = self.subInstr[ 'Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
709  for line in paperStr.strip().split('\n'):
710  d = dict(zip(self.cats, line.split()[1:]))
711  sizeDict[line.split()[0]] = d
712 
713  return sizeDict
714 
716  """!Class representing mapinfo instruction"""
717  def __init__(self, id):
718  InstructionObject.__init__(self, id = id)
719  self.type = 'mapinfo'
720  # default values
721  self.defaultInstruction = dict(unit = 'inch', where = (0, 0),
722  font = 'Helvetica', fontsize = 10, color = '0:0:0', background = 'none',
723  border = 'none', rect = None)
724  # current values
725  self.instruction = dict(self.defaultInstruction)
726 
727  def __str__(self):
728  instr = "mapinfo\n"
729  instr += " where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
730  instr += string.Template(" font $font\n fontsize $fontsize\n color $color\n").substitute(self.instruction)
731  instr += string.Template(" background $background\n border $border\n").substitute(self.instruction)
732  instr += " end"
733  return instr
734 
735  def Read(self, instruction, text):
736  """!Read instruction and save information"""
737  instr = {}
738  try:
739  for line in text:
740  sub = line.split(None,1)
741  if sub[0] == 'font':
742  instr['font'] = sub[1]
743  elif sub[0] == 'fontsize':
744  instr['fontsize'] = int(sub[1])
745  elif sub[0] == 'color':
746  instr['color'] = sub[1]
747  elif sub[0] == 'background':
748  instr['background'] = sub[1]
749  elif sub[0] == 'border':
750  instr['border'] = sub[1]
751  elif sub[0] == 'where':
752  instr['where'] = float(sub[1].split()[0]), float(sub[1].split()[1])
753  except (ValueError, IndexError):
754  GError(_("Failed to read instruction %s") % instruction)
755  return False
756  self.instruction.update(instr)
757  self.instruction['rect'] = self.EstimateRect(mapinfoDict = self.instruction)
758  return True
759 
760  def EstimateRect(self, mapinfoDict):
761  """!Estimate size to draw mapinfo"""
762  w = mapinfoDict['fontsize'] * 20 # any better estimation?
763  h = mapinfoDict['fontsize'] * 7
764  width = self.unitConv.convert(value = w, fromUnit = 'point', toUnit = 'inch')
765  height = self.unitConv.convert(value = h, fromUnit = 'point', toUnit = 'inch')
766  return Rect2D(x = float(mapinfoDict['where'][0]), y = float(mapinfoDict['where'][1]),
767  width = width, height = height)
768 
770  """!Class representing text instruction"""
771  def __init__(self, id):
772  InstructionObject.__init__(self, id = id)
773  self.type = 'text'
774  # default values
775  self.defaultInstruction = dict(text = "", font = "Helvetica", fontsize = 10, color = 'black', background = 'none',
776  hcolor = 'none', hwidth = 1, border = 'none', width = '1', XY = True,
777  where = (0,0), unit = 'inch', rotate = None,
778  ref = "center center", xoffset = 0, yoffset = 0, east = None, north = None)
779  # current values
780  self.instruction = dict(self.defaultInstruction)
781 
782  def __str__(self):
783  text = self.instruction['text'].replace('\n','\\n')
784  instr = u"text %s %s" % (self.instruction['east'], self.instruction['north'])
785  instr += " %s\n" % text
786  instr += (string.Template(" font $font\n fontsize $fontsize\n color $color\n").
787  substitute(self.instruction))
788  instr += string.Template(" hcolor $hcolor\n").substitute(self.instruction)
789  if self.instruction['hcolor'] != 'none':
790  instr += string.Template(" hwidth $hwidth\n").substitute(self.instruction)
791  instr += string.Template(" border $border\n").substitute(self.instruction)
792  if self.instruction['border'] != 'none':
793  instr += string.Template(" width $width\n").substitute(self.instruction)
794  instr += string.Template(" background $background\n").substitute(self.instruction)
795  if self.instruction["ref"] != '0':
796  instr += string.Template(" ref $ref\n").substitute(self.instruction)
797  if self.instruction["rotate"]:
798  instr += string.Template(" rotate $rotate\n").substitute(self.instruction)
799  if float(self.instruction["xoffset"]) or float(self.instruction["yoffset"]):
800  instr += (string.Template(" xoffset $xoffset\n yoffset $yoffset\n").
801  substitute(self.instruction))
802  instr += " end"
803  try:
804  instr = instr.encode('latin1')
805  except UnicodeEncodeError, err:
806  try:
807  pos = str(err).split('position')[1].split(':')[0].strip()
808  except IndexError:
809  pos = ''
810  if pos:
811  message = _("Characters on position %s are not supported "
812  "by ISO-8859-1 (Latin 1) encoding "
813  "which is required by module ps.map.") % pos
814  else:
815  message = _("Not all characters are supported "
816  "by ISO-8859-1 (Latin 1) encoding "
817  "which is required by module ps.map.")
818  GMessage(message = message)
819  return ''
820 
821  return instr
822 
823  def Read(self, instruction, text, **kwargs):
824  """!Read instruction and save information"""
825  map = kwargs['mapInstruction']
826  instr = {}
827  for line in text:
828  try:
829  sub = line.split(None, 1)[0]
830  if sub == 'text':
831  e, n = line.split(None, 3)[1:3]
832  if '%' in e and '%' in n:
833  instr['XY'] = True
834  instr['east'], instr['north'] = self.PercentToReal(e, n)
835  else:
836  instr['XY'] = False
837  instr['east'], instr['north'] = float(e), float(n)
838 
839  instr['text'] = line.split(None, 3)[3].decode('latin_1')
840 
841  elif sub == 'font':
842  instr['font'] = line.split(None, 1)[1]
843  elif sub == 'fontsize':
844  instr['fontsize'] = float(line.split(None, 1)[1])
845  elif sub == 'color':
846  instr['color'] = line.split(None, 1)[1]
847  elif sub == 'width':
848  instr['width'] = line.split(None, 1)[1]
849  elif sub == 'hcolor':
850  instr['hcolor'] = line.split(None, 1)[1]
851  elif sub == 'hwidth':
852  instr['hwidth'] = line.split(None, 1)[1]
853  elif sub == 'background':
854  instr['background'] = line.split(None, 1)[1]
855  elif sub == 'border':
856  instr['border'] = line.split(None, 1)[1]
857  elif sub == 'ref':
858  instr['ref'] = line.split(None, 1)[1]
859  elif sub == 'rotate':
860  instr['rotate'] = float(line.split(None, 1)[1])
861  elif sub == 'xoffset':
862  instr['xoffset'] = int(line.split(None, 1)[1])
863  elif sub == 'yoffset':
864  instr['yoffset'] = int(line.split(None, 1)[1])
865  elif sub == 'opaque':
866  if line.split(None, 1)[1].lower() in ('n', 'none'):
867  instr['background'] = 'none'
868 
869  except(IndexError, ValueError):
870  GError(_("Failed to read instruction %s") % instruction)
871  return False
872  instr['where'] = PaperMapCoordinates(mapInstr = map, x = instr['east'], y = instr['north'], paperToMap = False)
873  self.instruction.update(instr)
874 
875  return True
876 
878  """!Class representing eps instruction - image"""
879  def __init__(self, id, settings):
880  InstructionObject.__init__(self, id = id)
881  self.settings = settings
882  self.type = 'image'
883  # default values
884  self.defaultInstruction = dict(epsfile = "", XY = True, where = (0,0), unit = 'inch',
885  east = None, north = None,
886  rotate = None, scale = 1)
887  # current values
888  self.instruction = dict(self.defaultInstruction)
889 
890  def __str__(self):
891  self.ChangeRefPoint(toCenter = True)
892  epsfile = self.instruction['epsfile'].replace(os.getenv('GISBASE'), "$GISBASE")
893 
894  instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
895  instr += " epsfile %s\n" % epsfile
896  if self.instruction["rotate"]:
897  instr += string.Template(" rotate $rotate\n").substitute(self.instruction)
898  if self.instruction["scale"]:
899  instr += string.Template(" scale $scale\n").substitute(self.instruction)
900  instr += " end"
901  return instr
902 
903  def Read(self, instruction, text, **kwargs):
904  """!Read instruction and save information"""
905  mapInstr = kwargs['mapInstruction']
906  instr = {}
907  for line in text:
908  try:
909  sub = line.split(None, 1)[0]
910  if sub == 'eps':
911  e, n = line.split(None, 3)[1:3]
912  if '%' in e and '%' in n:
913  instr['XY'] = True
914  instr['east'], instr['north'] = self.PercentToReal(e, n)
915  else:
916  instr['XY'] = False
917  instr['east'], instr['north'] = float(e), float(n)
918 
919  elif sub == 'epsfile':
920  epsfile = line.split(None, 1)[1]
921  instr['epsfile'] = epsfile.replace("$GISBASE", os.getenv("GISBASE"))
922  elif sub == 'rotate':
923  instr['rotate'] = float(line.split(None, 1)[1])
924  elif sub == 'scale':
925  instr['scale'] = float(line.split(None, 1)[1])
926 
927  except(IndexError, ValueError):
928  GError(_("Failed to read instruction %s") % instruction)
929  return False
930  if not os.path.exists(instr['epsfile']):
931  GError(_("Failed to read instruction %(inst)s: "
932  "file %(file)s not found.") % { 'inst' : instruction,
933  'file' : instr['epsfile'] })
934  return False
935 
936  instr['epsfile'] = os.path.abspath(instr['epsfile'])
937  instr['size'] = self.GetImageOrigSize(instr['epsfile'])
938  if 'rotate' in instr:
939  instr['size'] = BBoxAfterRotation(instr['size'][0], instr['size'][1], instr['rotate'])
940  self.instruction.update(instr)
941  self.ChangeRefPoint(toCenter = False)
942  instr['where'] = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east'],
943  y = self.instruction['north'], paperToMap = False)
944  w = self.unitConv.convert(value = instr['size'][0], fromUnit = 'point', toUnit = 'inch')
945  h = self.unitConv.convert(value = instr['size'][1], fromUnit = 'point', toUnit = 'inch')
946  instr['rect'] = Rect2D(x = float(instr['where'][0]), y = float(instr['where'][1]),
947  width = w * self.instruction['scale'], height = h * self.instruction['scale'])
948  self.instruction.update(instr)
949 
950  return True
951 
952  def ChangeRefPoint(self, toCenter):
953  """!Change reference point (left top x center)"""
954  mapInstr = self.settings.FindInstructionByType('map')
955  if not mapInstr:
956  mapInstr = self.settings.FindInstructionByType('initMap')
957  mapId = mapInstr.id
958  if toCenter:
959  center = self.instruction['rect'].GetCentre()
960  ENCenter = PaperMapCoordinates(mapInstr = self.settings[mapId],
961  x = center[0], y = center[1], paperToMap = True)
962 
963  self.instruction['east'], self.instruction['north'] = ENCenter
964  else:
965  x, y = PaperMapCoordinates(mapInstr = self.settings[mapId], x = self.instruction['east'],
966  y = self.instruction['north'], paperToMap = False)
967  w = self.unitConv.convert(value = self.instruction['size'][0], fromUnit = 'point', toUnit = 'inch')
968  h = self.unitConv.convert(value = self.instruction['size'][1], fromUnit = 'point', toUnit = 'inch')
969  x -= w * self.instruction['scale'] / 2
970  y -= h * self.instruction['scale'] / 2
971  e, n = PaperMapCoordinates(mapInstr = self.settings[mapId], x = x, y = y, paperToMap = True)
972  self.instruction['east'], self.instruction['north'] = e, n
973 
974  def GetImageOrigSize(self, imagePath):
975  """!Get image size.
976 
977  If eps, size is read from image header.
978  """
979  fileName = os.path.split(imagePath)[1]
980  # if eps, read info from header
981  if os.path.splitext(fileName)[1].lower() == '.eps':
982  bbInfo = "%%BoundingBox"
983  file = open(imagePath,"r")
984  w = h = 0
985  while file:
986  line = file.readline()
987  if line.find(bbInfo) == 0:
988  w, h = line.split()[3:5]
989  break
990  file.close()
991  return float(w), float(h)
992  else: # we can use wx.Image
993  img = wx.Image(fileName, type=wx.BITMAP_TYPE_ANY)
994  return img.GetWidth(), img.GetHeight()
995 
997  """!Class representing eps instruction -- North Arrow"""
998  def __init__(self, id, settings):
999  Image.__init__(self, id = id, settings = settings)
1000  self.type = 'northArrow'
1001 
1002  def __str__(self):
1003  self.ChangeRefPoint(toCenter = True)
1004  epsfile = self.instruction['epsfile'].replace(os.getenv('GISBASE'), "$GISBASE")
1005 
1006  instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
1007  instr += "# north arrow\n"
1008  instr += " epsfile %s\n" % epsfile
1009  if self.instruction["rotate"]:
1010  instr += string.Template(" rotate $rotate\n").substitute(self.instruction)
1011  if self.instruction["scale"]:
1012  instr += string.Template(" scale $scale\n").substitute(self.instruction)
1013  instr += " end"
1014  return instr
1015 
1017  """!Class representing point instruction"""
1018  def __init__(self, id):
1019  InstructionObject.__init__(self, id = id)
1020  self.type = 'point'
1021  # default values
1022  self.defaultInstruction = dict(symbol = os.path.join('basic', 'x'),
1023  color = '0:0:0', fcolor = '200:200:200',
1024  rotate = 0, size = 10,
1025  XY = True, where = (0,0), unit = 'inch',
1026  east = None, north = None)
1027  # current values
1029 
1030  def __str__(self):
1031  instr = string.Template("point $east $north\n").substitute(self.instruction)
1032  instr += string.Template(" symbol $symbol\n").substitute(self.instruction)
1033  instr += string.Template(" color $color\n").substitute(self.instruction)
1034  instr += string.Template(" fcolor $fcolor\n").substitute(self.instruction)
1035  instr += string.Template(" rotate $rotate\n").substitute(self.instruction)
1036  instr += string.Template(" size $size\n").substitute(self.instruction)
1037  instr += " end"
1038  return instr
1039 
1040  def Read(self, instruction, text, **kwargs):
1041  """!Read instruction and save information"""
1042  mapInstr = kwargs['mapInstruction']
1043  instr = {}
1044  for line in text:
1045  try:
1046  sub = line.split(None, 1)[0]
1047  if sub == 'point':
1048  e, n = line.split(None, 3)[1:3]
1049  if '%' in e and '%' in n:
1050  instr['XY'] = True
1051  instr['east'], instr['north'] = self.PercentToReal(e, n)
1052  else:
1053  instr['XY'] = False
1054  instr['east'], instr['north'] = float(e), float(n)
1055 
1056  elif sub == 'symbol':
1057  instr['symbol'] = line.split(None, 1)[1]
1058  elif sub == 'rotate':
1059  instr['rotate'] = float(line.split(None, 1)[1])
1060  elif sub == 'size':
1061  instr['size'] = float(line.split(None, 1)[1])
1062  elif sub == 'color':
1063  instr['color'] = line.split(None, 1)[1]
1064  elif sub == 'fcolor':
1065  instr['fcolor'] = line.split(None, 1)[1]
1066 
1067 
1068  except(IndexError, ValueError):
1069  GError(_("Failed to read instruction %s") % instruction)
1070  return False
1071 
1072  self.instruction.update(instr)
1073  instr['where'] = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east'],
1074  y = self.instruction['north'], paperToMap = False)
1075  w = h = self.unitConv.convert(value = instr['size'], fromUnit = 'point', toUnit = 'inch')
1076  instr['rect'] = Rect2D(x = float(instr['where'][0]) - w / 2, y = float(instr['where'][1] - h / 2),
1077  width = w, height = h)
1078  self.instruction.update(instr)
1079 
1080  return True
1081 
1083  """!Class representing line instruction"""
1084  def __init__(self, id):
1085  InstructionObject.__init__(self, id = id)
1086  self.type = 'line'
1087  # default values
1088  self.defaultInstruction = dict(color = '0:0:0', width = 2,
1089  where = [wx.Point2D(), wx.Point2D()],
1090  east1 = None, north1 = None,
1091  east2 = None, north2 = None)
1092  # current values
1094 
1095  def __str__(self):
1096  instr = string.Template("line $east1 $north1 $east2 $north2\n").substitute(self.instruction)
1097  instr += string.Template(" color $color\n").substitute(self.instruction)
1098  instr += string.Template(" width $width\n").substitute(self.instruction)
1099  instr += " end\n"
1100  return instr
1101 
1102  def Read(self, instruction, text, **kwargs):
1103  """!Read instruction and save information"""
1104  mapInstr = kwargs['mapInstruction']
1105  instr = {}
1106  for line in text:
1107  try:
1108  sub = line.split(None, 1)[0]
1109  if sub == 'line':
1110  e1, n1, e2, n2 = line.split(None, 5)[1:5]
1111  if '%' in e1 and '%' in n1 and '%' in e2 and '%' in n2:
1112  instr['east1'], instr['north1'] = self.PercentToReal(e1, n1)
1113  instr['east2'], instr['north2'] = self.PercentToReal(e2, n2)
1114  else:
1115  instr['east1'], instr['north1'] = float(e1), float(n1)
1116  instr['east2'], instr['north2'] = float(e2), float(n2)
1117 
1118  elif sub == 'width':
1119  instr['width'] = float(line.split(None, 1)[1])
1120  elif sub == 'color':
1121  instr['color'] = line.split(None, 1)[1]
1122 
1123  except(IndexError, ValueError):
1124  GError(_("Failed to read instruction %s") % instruction)
1125  return False
1126 
1127  self.instruction.update(instr)
1128  e1, n1 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east1'],
1129  y = self.instruction['north1'], paperToMap = False)
1130  e2, n2 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east2'],
1131  y = self.instruction['north2'], paperToMap = False)
1132  instr['where'] = [wx.Point2D(e1, n1), wx.Point2D(e2, n2)]
1133  instr['rect'] = Rect2DPP(instr['where'][0], instr['where'][1])
1134  self.instruction.update(instr)
1135 
1136  return True
1137 
1139  """!Class representing rectangle instruction"""
1140  def __init__(self, id):
1141  InstructionObject.__init__(self, id = id)
1142  self.type = 'rectangle'
1143  # default values
1144  self.defaultInstruction = dict(color = '0:0:0', fcolor = 'none', width = 2,
1145  east1 = None, north1 = None,
1146  east2 = None, north2 = None)
1147  # current values
1149 
1150  def __str__(self):
1151  instr = string.Template("rectangle $east1 $north1 $east2 $north2\n").substitute(self.instruction)
1152  instr += string.Template(" color $color\n").substitute(self.instruction)
1153  instr += string.Template(" fcolor $fcolor\n").substitute(self.instruction)
1154  instr += string.Template(" width $width\n").substitute(self.instruction)
1155  instr += " end\n"
1156  return instr
1157 
1158  def Read(self, instruction, text, **kwargs):
1159  """!Read instruction and save information"""
1160  mapInstr = kwargs['mapInstruction']
1161  instr = {}
1162  for line in text:
1163  try:
1164  sub = line.split(None, 1)[0]
1165  if sub == 'rectangle':
1166  e1, n1, e2, n2 = line.split(None, 5)[1:5]
1167  if '%' in e1 and '%' in n1 and '%' in e2 and '%' in n2:
1168  instr['east1'], instr['north1'] = self.PercentToReal(e1, n1)
1169  instr['east2'], instr['north2'] = self.PercentToReal(e2, n2)
1170  else:
1171  instr['east1'], instr['north1'] = float(e1), float(n1)
1172  instr['east2'], instr['north2'] = float(e2), float(n2)
1173 
1174  elif sub == 'width':
1175  instr['width'] = float(line.split(None, 1)[1])
1176  elif sub == 'color':
1177  instr['color'] = line.split(None, 1)[1]
1178  elif sub == 'fcolor':
1179  instr['fcolor'] = line.split(None, 1)[1]
1180 
1181 
1182  except(IndexError, ValueError):
1183  GError(_("Failed to read instruction %s") % instruction)
1184  return False
1185 
1186  self.instruction.update(instr)
1187  e1, n1 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east1'],
1188  y = self.instruction['north1'], paperToMap = False)
1189  e2, n2 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east2'],
1190  y = self.instruction['north2'], paperToMap = False)
1191  instr['rect'] = Rect2DPP(wx.Point2D(e1, n1), wx.Point2D(e2, n2))
1192  self.instruction.update(instr)
1193 
1194  return True
1195 
1197  """!Class representing scalebar instruction"""
1198  def __init__(self, id):
1199  InstructionObject.__init__(self, id = id)
1200  self.type = 'scalebar'
1201  # default values
1202  self.defaultInstruction = dict(unit = 'inch', where = (1,1),
1203  unitsLength = 'auto', unitsHeight = 'inch',
1204  length = None, height = 0.1, rect = None,
1205  fontsize = 10, background = 'y',
1206  scalebar = 'f', segment = 4, numbers = 1)
1207  # current values
1209 
1210  def __str__(self):
1211  instr = string.Template("scalebar $scalebar\n").substitute(self.instruction)
1212  instr += " where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
1213  instr += string.Template(" length $length\n units $unitsLength\n").substitute(self.instruction)
1214  instr += string.Template(" height $height\n").substitute(self.instruction)
1215  instr += string.Template(" segment $segment\n numbers $numbers\n").substitute(self.instruction)
1216  instr += string.Template(" fontsize $fontsize\n background $background\n").substitute(self.instruction)
1217  instr += " end"
1218  return instr
1219 
1220  def Read(self, instruction, text, **kwargs):
1221  """!Read instruction and save information"""
1222  scale = kwargs['scale']
1223  instr = {}
1224  for line in text:
1225  try:
1226  if line.startswith('scalebar'):
1227  if 'scalebar s' in line:
1228  instr['scalebar'] = 's'
1229  else:
1230  instr['scalebar'] = 'f'
1231  elif line.startswith('where'):
1232  instr['where'] = map(float, line.split()[1:3])
1233  elif line.startswith('length'):
1234  instr['length'] = float(line.split()[1])
1235  elif line.startswith('units'):
1236  if line.split()[1] in ['auto', 'meters', 'kilometers', 'feet', 'miles', 'nautmiles']:
1237  instr['unitsLength'] = line.split()[1]
1238  elif line.startswith('height'):
1239  instr['height'] = float(line.split()[1])
1240  elif line.startswith('fontsize'):
1241  instr['fontsize'] = float(line.split()[1])
1242  elif line.startswith('numbers'):
1243  instr['numbers'] = int(line.split()[1])
1244  elif line.startswith('segment'):
1245  instr['segment'] = int(line.split()[1])
1246  elif line.startswith('background'):
1247  if line.split()[1].strip().lower() in ('y','yes'):
1248  instr['background'] = 'y'
1249  elif line.split()[1].strip().lower() in ('n','no', 'none'):
1250  instr['background'] = 'n'
1251  except(IndexError, ValueError):
1252  GError(_("Failed to read instruction %s") % instruction)
1253  return False
1254 
1255  self.instruction.update(instr)
1256  w, h = self.EstimateSize(scalebarDict = self.instruction, scale = scale)
1257  x = self.instruction['where'][0] - w / 2
1258  y = self.instruction['where'][1] - h / 2
1259  self.instruction['rect'] = Rect2D(x, y, w, h)
1260  return True
1261 
1262  def EstimateSize(self, scalebarDict, scale):
1263  """!Estimate size to draw scalebar"""
1264  units = projInfo()['units']
1265  if not units or units not in self.unitConv.getAllUnits():
1266  units = 'meters'
1267  if scalebarDict['unitsLength'] != 'auto':
1268  length = self.unitConv.convert(value = scalebarDict['length'], fromUnit = scalebarDict['unitsLength'], toUnit = 'inch')
1269  else:
1270  length = self.unitConv.convert(value = scalebarDict['length'], fromUnit = units, toUnit = 'inch')
1271 
1272  length *= scale
1273  length *= 1.1 #for numbers on the edge
1274  height = scalebarDict['height'] + 2 * self.unitConv.convert(value = scalebarDict['fontsize'], fromUnit = 'point', toUnit = 'inch')
1275  return (length, height)
1276 
1278  """!Class representing colortable instruction"""
1279  def __init__(self, id):
1280  InstructionObject.__init__(self, id = id)
1281  self.type = 'rasterLegend'
1282  # default values
1283  self.defaultInstruction = dict(rLegend = False, unit = 'inch', rasterDefault = True, raster = None,
1284  discrete = None, type = None,
1285  where = (0, 0),
1286  width = None, height = None, cols = 1, font = "Helvetica", fontsize = 10,
1287  #color = '0:0:0', tickbar = False, range = False, min = 0, max = 0,
1288  color = 'black', tickbar = 'n', range = False, min = 0, max = 0,
1289  nodata = 'n')
1290  # current values
1292 
1293  def __str__(self):
1294  instr = "colortable y\n"
1295  instr += string.Template(" raster $raster\n").substitute(self.instruction)
1296  instr += " where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
1297  if self.instruction['width']:
1298  instr += string.Template(" width $width\n").substitute(self.instruction)
1299  instr += string.Template(" discrete $discrete\n").substitute(self.instruction)
1300  if self.instruction['discrete'] == 'n':
1301  if self.instruction['height']:
1302  instr += string.Template(" height $height\n").substitute(self.instruction)
1303  instr += string.Template(" tickbar $tickbar\n").substitute(self.instruction)
1304  if self.instruction['range']:
1305  instr += string.Template(" range $min $max\n").substitute(self.instruction)
1306  else:
1307  instr += string.Template(" cols $cols\n").substitute(self.instruction)
1308  instr += string.Template(" nodata $nodata\n").substitute(self.instruction)
1309  instr += string.Template(" font $font\n fontsize $fontsize\n color $color\n")\
1310  .substitute(self.instruction)
1311  instr += " end"
1312  return instr
1313 
1314 
1315  def Read(self, instruction, text, **kwargs):
1316  """!Read instruction and save information"""
1317  instr = {}
1318  instr['rLegend'] = True
1319  for line in text:
1320  try:
1321  if line.startswith('where'):
1322  instr['where'] = map(float, line.split()[1:3])
1323  elif line.startswith('font '):
1324  instr['font'] = line.split()[1]
1325  elif line.startswith('fontsize'):
1326  instr['fontsize'] = float(line.split()[1])
1327  elif line.startswith('color '):
1328  instr['color'] = line.split()[1]
1329  elif line.startswith('raster'):
1330  instr['raster'] = line.split()[1]
1331  elif line.startswith('width'):
1332  instr['width'] = float(line.split()[1])
1333  elif line.startswith('height'):
1334  instr['height'] = float(line.split()[1])
1335  elif line.startswith('cols'):
1336  instr['cols'] = int(line.split()[1])
1337  elif line.startswith('range'):
1338  instr['range'] = True
1339  instr['min'] = float(line.split()[1])
1340  instr['max'] = float(line.split()[2])
1341  elif line.startswith('nodata'):
1342  if line.split()[1].strip().lower() in ('y','yes'):
1343  instr['nodata'] = 'y'
1344  elif line.split()[1].strip().lower() in ('n','no', 'none'):
1345  instr['nodata'] = 'n'
1346  elif line.startswith('tickbar'):
1347  if line.split()[1].strip().lower() in ('y','yes'):
1348  instr['tickbar'] = 'y'
1349  elif line.split()[1].strip().lower() in ('n','no', 'none'):
1350  instr['tickbar'] = 'n'
1351  elif line.startswith('discrete'):
1352  if line.split()[1].strip().lower() in ('y','yes'):
1353  instr['discrete'] = 'y'
1354  elif line.split()[1].strip().lower() in ('n','no', 'none'):
1355  instr['discrete'] = 'n'
1356 
1357  except(IndexError, ValueError):
1358  GError(_("Failed to read instruction %s") % instruction)
1359  return False
1360 
1361  if 'raster' in instr:
1362  instr['rasterDefault'] = False
1363  if 'discrete' not in instr:
1364  rasterType = getRasterType(map = instr['raster'])
1365  instr['type'] = rasterType
1366  if rasterType == 'CELL':
1367  instr['discrete'] = 'y'
1368  else:
1369  instr['discrete'] = 'n'
1370 
1371  else:
1372  instr['rasterDefault'] = True
1373  self.instruction.update(instr)
1374  # add 'rect' in the end
1375 
1376  return True
1377 
1378  def EstimateHeight(self, raster, discrete, fontsize, cols = None, height = None):
1379  """!Estimate height to draw raster legend"""
1380  if discrete == 'n':
1381  if height:
1382  height = height
1383  else:
1384  height = self.unitConv.convert(value = fontsize * 10,
1385  fromUnit = 'point', toUnit = 'inch')
1386 
1387  if discrete == 'y':
1388  if cols:
1389  cols = cols
1390  else:
1391  cols = 1
1392 
1393  rinfo = grass.raster_info(raster)
1394  if rinfo['datatype'] in ('DCELL', 'FCELL'):
1395  minim, maxim = rinfo['min'], rinfo['max']
1396  rows = ceil(maxim / cols )
1397  else:
1398  cat = grass.read_command('r.category', map = raster,
1399  fs = ':').strip().split('\n')
1400  rows = ceil(float(len(cat)) / cols )
1401 
1402 
1403  height = self.unitConv.convert(value = 1.5 * rows * fontsize, fromUnit = 'point', toUnit = 'inch')
1404 
1405  return height
1406 
1407  def EstimateWidth(self, raster, discrete, fontsize, cols = None, width = None, paperInstr = None):
1408  """!Estimate size to draw raster legend"""
1409 
1410  if discrete == 'n':
1411  rinfo = grass.raster_info(raster)
1412  minim, maxim = rinfo['min'], rinfo['max']
1413  if width:
1414  width = width
1415  else:
1416  width = self.unitConv.convert(value = fontsize * 2,
1417  fromUnit = 'point', toUnit = 'inch')
1418  text = len(max(str(minim), str(maxim), key = len))
1419  textPart = self.unitConv.convert(value = text * fontsize / 2,
1420  fromUnit = 'point', toUnit = 'inch')
1421  width += textPart
1422 
1423  elif discrete == 'y':
1424  if cols:
1425  cols = cols
1426  else:
1427  cols = 1
1428 
1429  if width:
1430  width = width
1431  else:
1432  paperWidth = paperInstr['Width'] - paperInstr['Right'] - paperInstr['Left']
1433  width = (paperWidth / cols) * (cols - 1) + 1
1434 
1435  return width
1436 
1438  """!Class representing colortable instruction"""
1439  def __init__(self, id):
1440  InstructionObject.__init__(self, id = id)
1441  self.type = 'vectorLegend'
1442  # default values
1443  self.defaultInstruction = dict(vLegend = False, unit = 'inch', where = (0, 0),
1444  defaultSize = True, width = 0.4, cols = 1, span = None,
1445  font = "Helvetica", fontsize = 10,
1446  border = 'none')
1447  # current values
1449 
1450  def __str__(self):
1451  instr = "vlegend\n"
1452  instr += " where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
1453  instr += string.Template(" font $font\n fontsize $fontsize\n").substitute(self.instruction)
1454  instr += string.Template(" width $width\n cols $cols\n").substitute(self.instruction)
1455  if self.instruction['span']:
1456  instr += string.Template(" span $span\n").substitute(self.instruction)
1457  instr += string.Template(" border $border\n").substitute(self.instruction)
1458  instr += " end"
1459  return instr
1460 
1461  def Read(self, instruction, text, **kwargs):
1462  """!Read instruction and save information"""
1463  instr = {}
1464  instr['vLegend'] = True
1465  for line in text:
1466  try:
1467  if line.startswith('where'):
1468  instr['where'] = map(float, line.split()[1:3])
1469  elif line.startswith('font '):
1470  instr['font'] = line.split()[1]
1471  elif line.startswith('fontsize'):
1472  instr['fontsize'] = float(line.split()[1])
1473  elif line.startswith('width'):
1474  instr['width'] = float(line.split()[1])
1475  elif line.startswith('cols'):
1476  instr['cols'] = int(line.split()[1])
1477  elif line.startswith('span'):
1478  instr['span'] = float(line.split()[1])
1479  elif line.startswith('border'):
1480  instr['border'] = line.split()[1]
1481 
1482  except(IndexError, ValueError):
1483  GError(_("Failed to read instruction %s") % instruction)
1484  return False
1485 
1486  self.instruction.update(instr)
1487 
1488  return True
1489 
1490  def EstimateSize(self, vectorInstr, fontsize, width = None, cols = None):
1491  """!Estimate size to draw vector legend"""
1492  if width:
1493  width = width
1494  else:
1495  width = fontsize/24.0
1496 
1497  if cols:
1498  cols = cols
1499  else:
1500  cols = 1
1501 
1502  vectors = vectorInstr['list']
1503  labels = [vector[4] for vector in vectors if vector[3] != 0]
1504  extent = (len(max(labels, key = len)) * fontsize / 2, fontsize)
1505  wExtent = self.unitConv.convert(value = extent[0], fromUnit = 'point', toUnit = 'inch')
1506  hExtent = self.unitConv.convert(value = extent[1], fromUnit = 'point', toUnit = 'inch')
1507  w = (width + wExtent) * cols
1508  h = len(labels) * hExtent / cols
1509  h *= 1.1
1510  return (w, h)
1511 
1512 
1514  """!Class representing raster instruction"""
1515  def __init__(self, id):
1516  InstructionObject.__init__(self, id = id)
1517  self.type = 'raster'
1518  # default values
1519  self.defaultInstruction = dict(isRaster = False, raster = None)
1520  # current values
1522 
1523  def __str__(self):
1524  instr = string.Template("raster $raster").substitute(self.instruction)
1525  return instr
1526 
1527  def Read(self, instruction, text):
1528  """!Read instruction and save information"""
1529  instr = {}
1530  instr['isRaster'] = True
1531  try:
1532  map = text.split()[1]
1533  except IndexError:
1534  GError(_("Failed to read instruction %s") % instruction)
1535  return False
1536  try:
1537  info = grass.find_file(map, element = 'cell')
1538  except grass.ScriptError, e:
1539  GError(message = e.value)
1540  return False
1541  instr['raster'] = info['fullname']
1542 
1543 
1544  self.instruction.update(instr)
1545  return True
1546 
1548  """!Class keeps vector layers"""
1549  def __init__(self, id):
1550  InstructionObject.__init__(self, id = id)
1551  self.type = 'vector'
1552  # default values
1553  self.defaultInstruction = dict(list = None)# [vmap, type, id, lpos, label]
1554  # current values
1556  def __str__(self):
1557  return ''
1558 
1559  def Read(self, instruction, text, **kwargs):
1560  """!Read instruction and save information"""
1561  instr = {}
1562 
1563  for line in text:
1564  if line.startswith('vpoints') or line.startswith('vlines') or line.startswith('vareas'):
1565  # subtype
1566  if line.startswith('vpoints'):
1567  subType = 'points'
1568  elif line.startswith('vlines'):
1569  subType = 'lines'
1570  elif line.startswith('vareas'):
1571  subType = 'areas'
1572  # name of vector map
1573  vmap = line.split()[1]
1574  try:
1575  info = grass.find_file(vmap, element = 'vector')
1576  except grass.ScriptError, e:
1577  GError(message = e.value)
1578  return False
1579  vmap = info['fullname']
1580  # id
1581  id = kwargs['id']
1582  # lpos
1583  lpos = kwargs['vectorMapNumber']
1584  #label
1585  label = '('.join(vmap.split('@')) + ')'
1586  break
1587  instr = [vmap, subType, id, lpos, label]
1588  if not self.instruction['list']:
1589  self.instruction['list'] = []
1590  self.instruction['list'].append(instr)
1591 
1592  return True
1593 
1595  """!Class represents instructions vareas, vlines, vpoints"""
1596  def __init__(self, id, subType):
1597  InstructionObject.__init__(self, id = id)
1598  self.type = 'vProperties'
1599  self.subType = subType
1600  # default values
1601  if self.subType == 'points':
1602  dd = dict(subType = 'points', name = None, type = 'point or centroid', connection = False, layer = '1',
1603  masked = 'n', color = '0:0:0', width = 1,
1604  fcolor = '255:0:0', rgbcolumn = None, symbol = os.path.join('basic', 'x'), eps = None,
1605  size = 5, sizecolumn = None, scale = None,
1606  rotation = False, rotate = 0, rotatecolumn = None, label = None, lpos = None)
1607  elif self.subType == 'lines':
1608  dd = dict(subType = 'lines', name = None, type = 'line or boundary', connection = False, layer = '1',
1609  masked = 'n', color = '0:0:0', hwidth = 1,
1610  hcolor = 'none', rgbcolumn = None,
1611  width = 1, cwidth = None,
1612  style = 'solid', linecap = 'butt', label = None, lpos = None)
1613  else: # areas
1614  dd = dict(subType = 'areas', name = None, connection = False, layer = '1',
1615  masked = 'n', color = '0:0:0', width = 1,
1616  fcolor = 'none', rgbcolumn = None,
1617  pat = None, pwidth = 1, scale = 1, label = None, lpos = None)
1619  # current values
1621 
1622  def __str__(self):
1623  dic = self.instruction
1624  vInstruction = string.Template("v$subType $name\n").substitute(dic)
1625  #data selection
1626  if self.subType in ('points', 'lines'):
1627  vInstruction += string.Template(" type $type\n").substitute(dic)
1628  if dic['connection']:
1629  vInstruction += string.Template(" layer $layer\n").substitute(dic)
1630  if dic.has_key('cats'):
1631  vInstruction += string.Template(" cats $cats\n").substitute(dic)
1632  elif dic.has_key('where'):
1633  vInstruction += string.Template(" where $where\n").substitute(dic)
1634  vInstruction += string.Template(" masked $masked\n").substitute(dic)
1635  #colors
1636  vInstruction += string.Template(" color $color\n").substitute(dic)
1637  if self.subType in ('points', 'areas'):
1638  if dic['color'] != 'none':
1639  vInstruction += string.Template(" width $width\n").substitute(dic)
1640  if dic['rgbcolumn']:
1641  vInstruction += string.Template(" rgbcolumn $rgbcolumn\n").substitute(dic)
1642  vInstruction += string.Template(" fcolor $fcolor\n").substitute(dic)
1643  else:
1644  if dic['rgbcolumn']:
1645  vInstruction += string.Template(" rgbcolumn $rgbcolumn\n").substitute(dic)
1646  elif dic['hcolor'] != 'none':
1647  vInstruction += string.Template(" hwidth $hwidth\n").substitute(dic)
1648  vInstruction += string.Template(" hcolor $hcolor\n").substitute(dic)
1649 
1650  # size and style
1651  if self.subType == 'points':
1652  if not dic['eps']:
1653  vInstruction += string.Template(" symbol $symbol\n").substitute(dic)
1654  else: #eps
1655  vInstruction += string.Template(" eps $eps\n").substitute(dic)
1656  if dic['size']:
1657  vInstruction += string.Template(" size $size\n").substitute(dic)
1658  else: # sizecolumn
1659  vInstruction += string.Template(" sizecolumn $sizecolumn\n").substitute(dic)
1660  vInstruction += string.Template(" scale $scale\n").substitute(dic)
1661  if dic['rotation']:
1662  if dic['rotate'] is not None:
1663  vInstruction += string.Template(" rotate $rotate\n").substitute(dic)
1664  else:
1665  vInstruction += string.Template(" rotatecolumn $rotatecolumn\n").substitute(dic)
1666 
1667  if self.subType == 'areas':
1668  if dic['pat'] is not None:
1669  patternFile = dic['pat'].replace(os.getenv("GISBASE"), "$GISBASE")
1670  vInstruction += " pat %s\n" % patternFile
1671  vInstruction += string.Template(" pwidth $pwidth\n").substitute(dic)
1672  vInstruction += string.Template(" scale $scale\n").substitute(dic)
1673 
1674  if self.subType == 'lines':
1675  if dic['width'] is not None:
1676  vInstruction += string.Template(" width $width\n").substitute(dic)
1677  else:
1678  vInstruction += string.Template(" cwidth $cwidth\n").substitute(dic)
1679  vInstruction += string.Template(" style $style\n").substitute(dic)
1680  vInstruction += string.Template(" linecap $linecap\n").substitute(dic)
1681  #position and label in vlegend
1682  vInstruction += string.Template(" label $label\n lpos $lpos\n").substitute(dic)
1683 
1684  vInstruction += " end"
1685  try:
1686  vInstruction = vInstruction.encode('Latin_1')
1687  except UnicodeEncodeError, err:
1688  try:
1689  pos = str(err).split('position')[1].split(':')[0].strip()
1690  except IndexError:
1691  pos = ''
1692  if pos:
1693  message = _("Characters on position %s are not supported "
1694  "by ISO-8859-1 (Latin 1) encoding "
1695  "which is required by module ps.map.") % pos
1696  else:
1697  message = _("Not all characters are supported "
1698  "by ISO-8859-1 (Latin 1) encoding "
1699  "which is required by module ps.map.")
1700  GMessage(message = message)
1701  return ''
1702  return vInstruction
1703 
1704  def Read(self, instruction, text, **kwargs):
1705  """!Read instruction and save information"""
1706  instr = {}
1707  try:
1708  info = grass.find_file(name = text[0].split()[1], element = 'vector')
1709  except grass.ScriptError, e:
1710  GError(message = e.value)
1711  return False
1712  instr['name'] = info['fullname']
1713  #connection
1714  instr['connection'] = True
1715  self.mapDBInfo = VectorDBInfo(instr['name'])
1716  self.layers = self.mapDBInfo.layers.keys()
1717  if not self.layers:
1718  instr['connection'] = False
1719 
1720  # points
1721  if text[0].startswith('vpoints'):
1722  for line in text[1:]:
1723  if line.startswith('type'):
1724  tp = []
1725  if line.find('point') != -1:
1726  tp.append('point')
1727  if line.find('centroid') != -1:
1728  tp.append('centroid')
1729  instr['type'] = ' or '.join(tp)
1730  elif line.startswith('fcolor'):
1731  instr['fcolor'] = line.split()[1]
1732  elif line.startswith('rgbcolumn'):
1733  instr['rgbcolumn'] = line.split()[1]
1734  elif line.startswith('symbol'):
1735  instr['symbol'] = line.split()[1]
1736  elif line.startswith('eps'):
1737  instr['eps'] = line.split()[1]
1738  elif line.startswith('size '):
1739  instr['size'] = line.split()[1]
1740  elif line.startswith('sizecolumn'):
1741  instr['size'] = None
1742  instr['sizecolumn'] = line.split()[1]
1743  elif line.startswith('scale '):
1744  instr['scale'] = float(line.split()[1])
1745  elif line.startswith('rotate '):
1746  instr['rotation'] = True
1747  instr['rotate'] = line.split()[1]
1748  elif line.startswith('rotatecolumn'):
1749  instr['rotatecolumn'] = line.split()[1]
1750  instr['rotation'] = True
1751  instr['rotate'] = None
1752 
1753  # lines
1754  elif text[0].startswith('vlines'):
1755  for line in text[1:]:
1756  if line.startswith('type'):
1757  tp = []
1758  if line.find('line') != -1:
1759  tp.append('line')
1760  if line.find('boundary') != -1:
1761  tp.append('boundary')
1762  instr['type'] = ' or '.join(tp)
1763  elif line.startswith('hwidth'):
1764  instr['hwidth'] = float(line.split()[1])
1765  elif line.startswith('hcolor'):
1766  instr['hcolor'] = line.split()[1]
1767  elif line.startswith('rgbcolumn'):
1768  instr['rgbcolumn'] = line.split()[1]
1769  elif line.startswith('cwidth'):
1770  instr['cwidth'] = float(line.split()[1])
1771  instr['width'] = None
1772  elif line.startswith('style'):
1773  instr['style'] = line.split()[1]
1774  elif line.startswith('linecap'):
1775  instr['linecap'] = line.split()[1]
1776 
1777  elif text[0].startswith('vareas'):
1778  for line in text[1:]:
1779  if line.startswith('fcolor'):
1780  instr['fcolor'] = line.split()[1]
1781  elif line.startswith('pat'):
1782  patternFile = line.split()[1]
1783  instr['pat'] = patternFile.replace("$GISBASE", os.getenv("GISBASE"))
1784  elif line.startswith('pwidth'):
1785  instr['pwidth'] = float(line.split()[1])
1786  elif line.startswith('scale'):
1787  instr['scale'] = float(line.split()[1])
1788 
1789 
1790  # same properties for all
1791  for line in text[1:]:
1792  if line.startswith('lpos'):
1793  instr['lpos'] = int(line.split()[1])
1794  elif line.startswith('label'):
1795  instr['label'] = line.split(None, 1)[1].decode('latin_1')
1796  elif line.startswith('layer'):
1797  instr['layer'] = line.split()[1]
1798  elif line.startswith('masked'):
1799  if line.split()[1].lower() in ('y', 'yes'):
1800  instr['masked'] = 'y'
1801  else:
1802  instr['masked'] = 'n'
1803  elif line.startswith('color'):
1804  instr['color'] = line.split()[1]
1805  elif line.startswith('rgbcolumn'):
1806  instr['rgbcolumn'] = line.split()[1]
1807  elif line.startswith('width'):
1808  instr['width'] = float(line.split()[1])
1809 
1810  if 'label' not in instr:
1811  instr['label'] = '('.join(instr['name'].split('@')) + ')'
1812  if 'lpos' not in instr:
1813  instr['lpos'] = kwargs['vectorMapNumber']
1814  self.instruction.update(instr)
1815 
1816  return True
def CmdToTuple
Convert command list to tuple for gcmd.RunCommand()
Definition: core/utils.py:527
def decode
Definition: core.py:80
def Read
Read instruction and save information.
def Read
Read instruction and save information.
def Read
Read instruction and save information.
def projInfo
Return region projection and map units information, taken from render.py.
Definition: psmap/utils.py:309
wxGUI command interface
def GetCmdString
Definition: core/utils.py:499
def getRasterType
Returns type of raster map (CELL, FCELL, DCELL)
Definition: psmap/utils.py:349
def PaperMapCoordinates
Converts paper (inch) coordinates &lt;-&gt; map coordinates.
Definition: psmap/utils.py:159
def GetInstruction
Get current values.
def EstimateHeight
Estimate height to draw raster legend.
Class representing colortable instruction.
def Read
Read instruction and save them.
def __str__
Returns particular part of text instruction.
def __contains__
Test if instruction is included.
Definition: instructions.py:76
def Read
Read instruction and save information.
Class representing scalebar instruction.
def ChangeRefPoint
Change reference point (left top x center)
def Read
Read instruction and save information.
Class representing text instruction.
def SetRegion
Sets region from file comment or sets current region in case of no comment.
def Read
Read instruction and save information.
def SetResolution
If resolution is too high, lower it.
Definition: psmap/utils.py:259
def Read
Read instruction and save information.
Class representing rectangle instruction.
#define max(x, y)
Definition: draw2.c:69
struct tm * localtime()
def EstimateRect
Estimate size to draw mapinfo.
def Read
Read instruction and save information.
def Read
Read instruction and save information.
def Read
Read instruction and save information.
def GetImageOrigSize
Get image size.
def split
Platform spefic shlex.split.
Definition: core/utils.py:37
def EstimateSize
Estimate size to draw scalebar.
def FindInstructionByType
Find instruction(s) with the given type.
Class representing map (instructions maploc, scale, border)
def BBoxAfterRotation
Compute bounding box or rotated rectangle.
Definition: psmap/utils.py:383
def __str__
Returns text for instruction file.
Definition: instructions.py:57
Class representing virtual map.
Class keeps vector layers.
utilities for wxpsmap (classes, functions)
Class representing mapinfo instruction.
Class representing line instruction.
def SetInstruction
Set default values.
def Read
Read instruction and save information.
def AddInstruction
Add instruction.
def Read
Read instruction and save information.
def __delitem__
Delete instruction.
Definition: instructions.py:83
Class representing eps instruction - image.
Misc utilities for wxGUI.
Abtract class representing single instruction.
def Read
Read instruction and save information.
Class representing point instruction.
def GetMapBounds
Run ps.map -b to get information about map bounding box.
Definition: psmap/utils.py:331
def EstimateWidth
Estimate size to draw raster legend.
Class representing eps instruction – North Arrow.
Class representing page instruction.
Class representing raster instruction.
Class represents instructions vareas, vlines, vpoints.
def Read
Read instruction and save information.
def Read
Reads instruction file and creates instruction objects.
Class representing colortable instruction.
def PercentToReal
Converts text coordinates from percent of region to map coordinates.
Class which represents instruction file.
Definition: instructions.py:48
def EstimateSize
Estimate size to draw vector legend.
def RunCommand
Run GRASS command.
Definition: gcmd.py:625