""" @package psmap.instructions @brief Map feature objects Classes: - dialogs::Instruction - dialogs::InstructionObject - dialogs::InitMap - dialogs::MapFrame - dialogs::PageSetup - dialogs::Mapinfo - dialogs::Text - dialogs::Image - dialogs::NorthArrow - dialogs::Point - dialogs::Line - dialogs::Rectangle - dialogs::Scalebar - dialogs::RasterLegend - dialogs::VectorLegend - dialogs::Raster - dialogs::Vector - dialogs::VProperties (C) 2011-2012 by Anna Kratochvilova, and the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. @author Anna Kratochvilova (bachelor's project) @author Martin Landa (mentor) """ import os import string import six from math import ceil from time import strftime, localtime import wx import grass.script as grass from grass.script.task import cmdlist_to_tuple from core.gcmd import RunCommand, GError, GMessage, GWarning from core.utils import GetCmdString from dbmgr.vinfo import VectorDBInfo from psmap.utils import * class Instruction: """Class which represents instruction file""" def __init__(self, parent, objectsToDraw): self.parent = parent self.objectsToDraw = objectsToDraw # here are kept objects like mapinfo, rasterlegend, etc. self.instruction = list() def __str__(self): """Returns text for instruction file""" comment = "# timestamp: " + strftime("%Y-%m-%d %H:%M", localtime()) + '\n' env = grass.gisenv() comment += "# location: %s\n" % env['LOCATION_NAME'] comment += "# mapset: %s\n" % env['MAPSET'] comment += "# page orientation: %s\n" % self.FindInstructionByType('page')[ 'Orientation'] border = '' if not self.FindInstructionByType('map'): border = 'border n\n' text = [str(each) for each in self.instruction] return comment + border + '\n'.join(text) + '\nend' def __getitem__(self, id): for each in self.instruction: if each.id == id: return each return None def __contains__(self, id): """Test if instruction is included""" for each in self.instruction: if each.id == id: return True return False def __delitem__(self, id): """Delete instruction""" for each in self.instruction: if each.id == id: if each.type == 'map': # must remove raster, vector layers too vektor = self.FindInstructionByType('vector', list=True) vProperties = self.FindInstructionByType( 'vProperties', list=True) raster = self.FindInstructionByType('raster', list=True) for item in vektor + vProperties + raster: if item in self.instruction: self.instruction.remove(item) self.instruction.remove(each) if id in self.objectsToDraw: self.objectsToDraw.remove(id) return def AddInstruction(self, instruction): """Add instruction""" # add to instructions if instruction.type == 'map': self.instruction.insert(0, instruction) else: self.instruction.append(instruction) # add to drawable objects if instruction.type not in ( 'page', 'raster', 'vector', 'vProperties', 'initMap'): if instruction.type == 'map': self.objectsToDraw.insert(0, instruction.id) else: self.objectsToDraw.append(instruction.id) def FindInstructionByType(self, type, list=False): """Find instruction(s) with the given type""" inst = [] for each in self.instruction: if each.type == type: inst.append(each) if len(inst) == 1 and not list: return inst[0] return inst def Read(self, filename): """Reads instruction file and creates instruction objects""" self.filename = filename # open file try: file = open(filename, 'r') except IOError: GError(message=_("Unable to open file\n%s") % filename) return # first read file to get information about region and scaletype isRegionComment = False orientation = 'Portrait' for line in file: if '# g.region' in line: self.SetRegion(regionInstruction=line) isRegionComment = True break if '# page orientation' in line: orientation = line.split(':')[-1].strip() if not isRegionComment: self.SetRegion(regionInstruction=None) # then run ps.map -b to get information for maploc # compute scale and center map = self.FindInstructionByType('map') region = grass.region() map['center'] = (region['n'] + region['s'] ) / 2, (region['w'] + region['e']) / 2 mapRect = GetMapBounds( self.filename, portrait=( orientation == 'Portrait')) map['rect'] = mapRect proj = projInfo() toM = 1.0 if proj['units']: toM = float(proj['meters']) units = UnitConversion(self.parent) w = units.convert( value=mapRect.Get()[2], fromUnit='inch', toUnit='meter') / toM map['scale'] = w / abs((region['w'] - region['e'])) SetResolution( dpi=300, width=map['rect'].width, height=map['rect'].height) # read file again, now with information about map bounds isBuffer = False buffer = [] instruction = None vectorMapNumber = 1 file.seek(0) for line in file: if not line.strip(): continue line = line.strip() if isBuffer: buffer.append(line) if 'end' in line: isBuffer = False kwargs = {} if instruction == 'scalebar': kwargs['scale'] = map['scale'] elif instruction in ('text', 'eps', 'point', 'line', 'rectangle'): kwargs['mapInstruction'] = map elif instruction in ('vpoints', 'vlines', 'vareas'): kwargs['id'] = wx.NewId() kwargs['vectorMapNumber'] = vectorMapNumber vectorMapNumber += 1 elif instruction == 'paper': kwargs['Orientation'] = orientation ok = self.SendToRead(instruction, buffer, **kwargs) if not ok: return False buffer = [] continue elif line.startswith('paper'): instruction = 'paper' isBuffer = True buffer.append(line) elif line.startswith('border'): if line.split()[1].lower() in ('n', 'no', 'none'): ok = self.SendToRead('border', [line]) if not ok: return False elif line.split()[1].lower() in ('y', 'yes'): instruction = 'border' isBuffer = True buffer.append(line) elif line.startswith('scale '): if isBuffer: continue ok = self.SendToRead( 'scale', line, isRegionComment=isRegionComment) if not ok: return False elif line.startswith('maploc'): ok = self.SendToRead(instruction='maploc', text=line) if not ok: return False elif line.startswith('raster'): ok = self.SendToRead(instruction='raster', text=line) if not ok: return False elif line.startswith('mapinfo'): instruction = 'mapinfo' isBuffer = True buffer.append(line) elif line.startswith('scalebar'): instruction = 'scalebar' isBuffer = True buffer.append(line) elif line.startswith('text'): instruction = 'text' isBuffer = True buffer.append(line) elif line.startswith('eps'): instruction = 'eps' isBuffer = True buffer.append(line) elif line.startswith('point'): instruction = 'point' isBuffer = True buffer.append(line) elif line.startswith('line'): instruction = 'line' isBuffer = True buffer.append(line) elif line.startswith('rectangle'): instruction = 'rectangle' isBuffer = True buffer.append(line) elif line.startswith('colortable'): if len(line.split()) == 2 and line.split()[ 1].lower() in ('n', 'no', 'none'): break instruction = 'colortable' isBuffer = True buffer.append(line) elif line.startswith('vlegend'): instruction = 'vlegend' isBuffer = True buffer.append(line) elif line.startswith('vpoints'): instruction = 'vpoints' isBuffer = True buffer.append(line) elif line.startswith('vlines'): instruction = 'vlines' isBuffer = True buffer.append(line) elif line.startswith('vareas'): instruction = 'vareas' isBuffer = True buffer.append(line) elif line.startswith('labels'): instruction = 'labels' isBuffer = True buffer.append(line) rasterLegend = self.FindInstructionByType('rasterLegend') raster = self.FindInstructionByType('raster') page = self.FindInstructionByType('page') vector = self.FindInstructionByType('vector') vectorLegend = self.FindInstructionByType('vectorLegend') vectorMaps = self.FindInstructionByType('vProperties', list=True) # check (in case of scaletype 0) if map is drawn also map['drawMap'] = False if map['scaleType'] == 0: mapForRegion = map['map'] if map['mapType'] == 'raster' and raster: if mapForRegion == raster['raster']: map['drawMap'] = True elif map['mapType'] == 'vector' and vector: for vmap in vector['list']: if mapForRegion == vmap[0]: map['drawMap'] = True # rasterLegend if rasterLegend: if rasterLegend['rasterDefault'] and raster: rasterLegend['raster'] = raster['raster'] if not rasterLegend['discrete']: rasterType = getRasterType(map=rasterLegend['raster']) if rasterType == 'CELL': rasterLegend['discrete'] = 'y' else: rasterLegend['discrete'] = 'n' # estimate size height = rasterLegend.EstimateHeight( raster=rasterLegend['raster'], discrete=rasterLegend['discrete'], fontsize=rasterLegend['fontsize'], cols=rasterLegend['cols'], height=rasterLegend['height']) width = rasterLegend.EstimateWidth( raster=rasterLegend['raster'], discrete=rasterLegend['discrete'], fontsize=rasterLegend['fontsize'], cols=rasterLegend['cols'], width=rasterLegend['width'], paperInstr=page) rasterLegend['rect'] = Rect2D( x=float(rasterLegend['where'][0]), y=float(rasterLegend['where'][1]), width=width, height=height) # vectors, vlegend if vector: for vmap in vectorMaps: for i, each in enumerate(vector['list']): if each[2] == vmap.id: vector['list'][i][4] = vmap['label'] vector['list'][i][3] = vmap['lpos'] if vectorLegend: size = vectorLegend.EstimateSize( vectorInstr=vector, fontsize=vectorLegend['fontsize'], width=vectorLegend['width'], cols=vectorLegend['cols']) vectorLegend['rect'] = Rect2D( x=float(vectorLegend['where'][0]), y=float(vectorLegend['where'][1]), width=size[0], height=size[1]) page = self.FindInstructionByType('page') if not page: page = PageSetup(wx.NewId()) self.AddInstruction(page) else: page['Orientation'] = orientation # return True def SendToRead(self, instruction, text, **kwargs): psmapInstrDict = dict(paper=['page'], maploc=['map'], scale=['map'], border=['map'], raster=['raster'], mapinfo=['mapinfo'], scalebar=['scalebar'], text=['text'], eps=['image', 'northArrow'], point=['point'], line=['line'], rectangle=['rectangle'], vpoints=['vector', 'vProperties'], vlines=['vector', 'vProperties'], vareas=['vector', 'vProperties'], colortable=['rasterLegend'], vlegend=['vectorLegend'], labels=['labels'] ) myInstrDict = dict(page=PageSetup, map=MapFrame, raster=Raster, mapinfo=Mapinfo, scalebar=Scalebar, text=Text, image=Image, northArrow=NorthArrow, point=Point, line=Line, rectangle=Rectangle, rasterLegend=RasterLegend, vectorLegend=VectorLegend, vector=Vector, vProperties=VProperties, labels=Labels ) myInstruction = psmapInstrDict[instruction] for i in myInstruction: instr = self.FindInstructionByType(i) if i in ('text', 'vProperties', 'image', 'northArrow', 'point', 'line', 'rectangle') or not instr: id = wx.NewId() # !vProperties expect subtype if i == 'vProperties': id = kwargs['id'] newInstr = myInstrDict[i](id, subType=instruction[1:]) elif i in ('image', 'northArrow'): commentFound = False for line in text: if line.find("# north arrow") >= 0: commentFound = True if i == 'image' and commentFound or \ i == 'northArrow' and not commentFound: continue newInstr = myInstrDict[i](id, settings=self) else: newInstr = myInstrDict[i](id) ok = newInstr.Read(instruction, text, **kwargs) if ok: self.AddInstruction(newInstr) else: return False else: ok = instr.Read(instruction, text, **kwargs) if not ok: return False return True def SetRegion(self, regionInstruction): """Sets region from file comment or sets current region in case of no comment""" map = MapFrame(wx.NewId()) self.AddInstruction(map) if regionInstruction: cmd = cmdlist_to_tuple(regionInstruction.strip('# ').split()) # define scaleType if len(cmd[1]) <= 3: if 'raster' in cmd[1]: map['scaleType'] = 0 map['mapType'] = 'raster' map['map'] = cmd[1]['raster'] elif 'vector' in cmd[1]: map['scaleType'] = 0 map['mapType'] = 'vector' map['map'] = cmd[1]['vector'] elif 'region' in cmd[1]: map['scaleType'] = 1 map['region'] = cmd[1]['region'] else: map['scaleType'] = 2 else: map['scaleType'] = 2 grass.del_temp_region() region = grass.region() grass.use_temp_region() cmd = ['g.region', region] cmdString = GetCmdString(cmd).replace('g.region', '') GMessage( _("Instruction file will be loaded with following region: %s\n") % cmdString) try: RunCommand(cmd[0], **cmd[1]) except grass.ScriptError as e: GError(_("Region cannot be set\n%s") % e) return False class InstructionObject: """Abtract class representing single instruction""" def __init__(self, id): self.id = id # default values self.defaultInstruction = dict() # current values self.instruction = self.defaultInstruction # converting units self.unitConv = UnitConversion() def __str__(self): """Returns particular part of text instruction""" return '' def __getitem__(self, key): for each in self.instruction.keys(): if each == key: return self.instruction[key] return None def __setitem__(self, key, value): self.instruction[key] = value def GetInstruction(self): """Get current values""" return self.instruction def SetInstruction(self, instruction): """Set default values""" self.instruction = instruction def Read(self, instruction, text, **kwargs): """Read instruction and save them""" pass def PercentToReal(self, e, n): """Converts text coordinates from percent of region to map coordinates""" e, n = float(e.strip('%')), float(n.strip('%')) region = grass.region() N = region['s'] + (region['n'] - region['s']) / 100 * n E = region['w'] + (region['e'] - region['w']) / 100 * e return E, N class InitMap(InstructionObject): """Class representing virtual map""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'initMap' # default values self.defaultInstruction = dict(rect=None, scale=None) # current values self.instruction = dict(self.defaultInstruction) class MapFrame(InstructionObject): """Class representing map (instructions maploc, scale, border)""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'map' # default values self.defaultInstruction = dict( map=None, mapType=None, drawMap=True, region=None, rect=Rect2D(), scaleType=0, scale=None, center=None, resolution=300, border='y', width=1, color='0:0:0') # current values self.instruction = dict(self.defaultInstruction) def __str__(self): instr = '' comment = '' # region settings region = grass.region() if self.instruction['scaleType'] == 0: # match map map = self.instruction['map'] if self.instruction['mapType'] == 'raster': comment = "# g.region raster=%s nsres=%s ewres=%s\n" % ( map, region['nsres'], region['ewres']) else: comment = "# g.region vector=%s\n" % (map) elif self.instruction['scaleType'] == 1: # saved region region = self.instruction['region'] comment = "# g.region region=%s\n" % region # current region, fixed scale elif self.instruction['scaleType'] in (2, 3): comment = string.Template( "# g.region n=$n s=$s e=$e w=$w rows=$rows cols=$cols \n").substitute(**region) instr += comment instr += '\n' # maploc maplocInstruction = "maploc %.3f %.3f" % ( self.instruction['rect'].x, self.instruction['rect'].y) if self.instruction['scaleType'] != 3: maplocInstruction += " %.3f %.3f" % ( self.instruction['rect'].width, self.instruction['rect'].height) instr += maplocInstruction instr += '\n' # scale if self.instruction['scaleType'] == 3: # fixed scale scaleInstruction = "scale 1:%.0f" % (1 / self.instruction['scale']) instr += scaleInstruction instr += '\n' # border borderInstruction = '' if self.instruction['border'] == 'n': borderInstruction = "border n" else: borderInstruction = "border y\n" borderInstruction += string.Template( " width $width\n color $color\n").substitute( self.instruction) borderInstruction += " end" instr += borderInstruction instr += '\n' return instr def Read(self, instruction, text, **kwargs): """Read instruction and save information""" if 'isRegionComment' in kwargs: isRegionComment = kwargs['isRegionComment'] instr = {} if instruction == 'border': for line in text: if line.startswith('end'): break try: if line.split()[1].lower() in ('n', 'no', 'none'): instr['border'] = 'n' break elif line.split()[1].lower() in ('y', 'yes'): instr['border'] = 'y' elif line.startswith('width'): instr['width'] = line.split()[1] elif line.startswith('color'): instr['color'] = line.split()[1] except IndexError: GError(_("Failed to read instruction %s") % instruction) return False elif instruction == 'scale': try: scaleText = text.strip('scale ').split(':')[1] # when scale instruction given and region comment also, then # scaletype is fixed scale if not isRegionComment: instr['scaleType'] = 2 else: instr['scaleType'] = 3 scale = 1 / float(scaleText) if abs(scale - self.instruction['scale']) > (0.01 * scale): GWarning(_("Scale has changed, old value: %(old)s\nnew value: %(new)s") % {'old': scale, 'new': self.instruction['scale']}) except (ValueError, IndexError): GError( _("Failed to read instruction %s.\nUse 1:25000 notation.") % instruction) return False elif instruction == 'maploc': maploc = text.strip('maploc ').split() if len(maploc) >= 2: if abs(self.instruction['rect'].Get()[0] - float(maploc[0])) > 0.5 or \ abs(self.instruction['rect'].Get()[1] - float(maploc[1])) > 0.5: GWarning( _("Map frame position changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % { 'old1': maploc[0], 'old2': maploc[1], 'new1': self.instruction['rect'].Get()[0], 'new2': self.instruction['rect'].Get()[1]}) #instr['rect'] = wx.Rect2D(float(maploc[0]), float(maploc[1]), self.instruction['rect'][2], self.instruction['rect'][3]) if len(maploc) == 4: if abs(self.instruction['rect'].Get()[2] - float(maploc[2])) > 0.5 or \ abs(self.instruction['rect'].Get()[3] - float(maploc[3])) > 0.5: GWarning( _("Map frame size changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % { 'old1': maploc[2], 'old2': maploc[3], 'new1': self.instruction['rect'].Get()[2], 'new2': self.instruction['rect'].Get()[3]}) #instr['rect'] = wx.Rect2D(*map(float, maploc)) self.instruction.update(instr) return True class PageSetup(InstructionObject): """Class representing page instruction""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'page' # default values self.defaultInstruction = dict( Units='inch', Format='a4', Orientation='Portrait', Width=8.268, Height=11.693, Left=0.5, Right=0.5, Top=1, Bottom=1) # current values self.instruction = dict(self.defaultInstruction) def __str__(self): if self.instruction['Format'] == 'custom': instr = string.Template( "paper\n width $Width\n height $Height\n").substitute( self.instruction) else: instr = string.Template( "paper $Format\n").substitute(self.instruction) instr += string.Template( " left $Left\n right $Right\n bottom $Bottom\n top $Top\n end").substitute(self.instruction) return instr def Read(self, instruction, text, **kwargs): """Read instruction and save information""" instr = {} self.cats = ['Width', 'Height', 'Left', 'Right', 'Top', 'Bottom'] self.subInstr = dict( zip(['width', 'height', 'left', 'right', 'top', 'bottom'], self.cats)) if instruction == 'paper': # just for sure for line in text: if line.startswith('paper'): if len(line.split()) > 1: pformat = line.split()[1] availableFormats = self._toDict( grass.read_command( 'ps.map', flags='p', quiet=True)) # e.g. paper a3 try: instr['Format'] = pformat for key, value in six.iteritems(availableFormats[ pformat]): instr[key] = float(value) break except KeyError: GError( _("Failed to read instruction %(file)s.\nUnknown format %(for)s") % { 'file': instruction, 'for': format}) return False else: # paper # width ... instr['Format'] = 'custom' # read subinstructions elif instr['Format'] == 'custom' and not line.startswith('end'): text = line.split() try: instr[self.subInstr[text[0]]] = float(text[1]) except (IndexError, KeyError): GError( _("Failed to read instruction %s.") % instruction) return False if 'Orientation' in kwargs and kwargs[ 'Orientation'] == 'Landscape': instr['Width'], instr['Height'] = instr[ 'Height'], instr['Width'] self.instruction.update(instr) return True def _toDict(self, paperStr): sizeDict = dict() # cats = self.subInstr[ 'Width', 'Height', 'Left', 'Right', 'Top', 'Bottom'] for line in paperStr.strip().split('\n'): d = dict(zip(self.cats, line.split()[1:])) sizeDict[line.split()[0]] = d return sizeDict class Mapinfo(InstructionObject): """Class representing mapinfo instruction""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'mapinfo' # default values self.defaultInstruction = dict( unit='inch', where=( 0, 0), font='Helvetica', fontsize=10, color='0:0:0', background='none', border='none', rect=None) # current values self.instruction = dict(self.defaultInstruction) def __str__(self): instr = "mapinfo\n" instr += " where %.3f %.3f\n" % ( self.instruction['where'][0], self.instruction['where'][1]) instr += string.Template( " font $font\n fontsize $fontsize\n color $color\n").substitute(self.instruction) instr += string.Template( " background $background\n border $border\n").substitute( self.instruction) instr += " end" return instr def Read(self, instruction, text): """Read instruction and save information""" instr = {} try: for line in text: sub = line.split(None, 1) if sub[0] == 'font': instr['font'] = sub[1] elif sub[0] == 'fontsize': instr['fontsize'] = int(sub[1]) elif sub[0] == 'color': instr['color'] = sub[1] elif sub[0] == 'background': instr['background'] = sub[1] elif sub[0] == 'border': instr['border'] = sub[1] elif sub[0] == 'where': instr['where'] = float( sub[1].split()[0]), float( sub[1].split()[1]) except (ValueError, IndexError): GError(_("Failed to read instruction %s") % instruction) return False self.instruction.update(instr) self.instruction['rect'] = self.EstimateRect( mapinfoDict=self.instruction) return True def EstimateRect(self, mapinfoDict): """Estimate size to draw mapinfo""" w = mapinfoDict['fontsize'] * 20 # any better estimation? h = mapinfoDict['fontsize'] * 7 width = self.unitConv.convert(value=w, fromUnit='point', toUnit='inch') height = self.unitConv.convert( value=h, fromUnit='point', toUnit='inch') return Rect2D(x=float(mapinfoDict['where'][0]), y=float( mapinfoDict['where'][1]), width=width, height=height) class Text(InstructionObject): """Class representing text instruction""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'text' # default values self.defaultInstruction = dict( text="", font="Helvetica", fontsize=10, color='black', background='none', hcolor='none', hwidth=1, border='none', width='1', XY=True, where=(0, 0), unit='inch', rotate=None, ref="center center", xoffset=0, yoffset=0, east=None, north=None) # current values self.instruction = dict(self.defaultInstruction) def __str__(self): text = self.instruction['text'].replace('\n', '\\n') instr = u"text %s %s" % ( self.instruction['east'], self.instruction['north']) instr += " %s\n" % text instr += ( string.Template(" font $font\n fontsize $fontsize\n color $color\n"). substitute( self.instruction)) instr += string.Template(" hcolor $hcolor\n").substitute(self.instruction) if self.instruction['hcolor'] != 'none': instr += string.Template( " hwidth $hwidth\n").substitute(self.instruction) instr += string.Template(" border $border\n").substitute(self.instruction) if self.instruction['border'] != 'none': instr += string.Template( " width $width\n").substitute(self.instruction) instr += string.Template( " background $background\n").substitute(self.instruction) if self.instruction["ref"] != '0': instr += string.Template(" ref $ref\n").substitute(self.instruction) if self.instruction["rotate"]: instr += string.Template( " rotate $rotate\n").substitute(self.instruction) if float( self.instruction["xoffset"]) or float( self.instruction["yoffset"]): instr += ( string.Template(" xoffset $xoffset\n yoffset $yoffset\n"). substitute( self.instruction)) instr += " end" try: instr = instr.encode('latin1') except UnicodeEncodeError as err: try: pos = str(err).split('position')[1].split(':')[0].strip() except IndexError: pos = '' if pos: message = _("Characters on position %s are not supported " "by ISO-8859-1 (Latin 1) encoding " "which is required by module ps.map.") % pos else: message = _("Not all characters are supported " "by ISO-8859-1 (Latin 1) encoding " "which is required by module ps.map.") GMessage(message=message) return '' return instr def Read(self, instruction, text, **kwargs): """Read instruction and save information""" map = kwargs['mapInstruction'] instr = {} for line in text: try: sub = line.split(None, 1)[0] if sub == 'text': e, n = line.split(None, 3)[1:3] if '%' in e and '%' in n: instr['XY'] = True instr['east'], instr[ 'north'] = self.PercentToReal(e, n) else: instr['XY'] = False instr['east'], instr['north'] = float(e), float(n) instr['text'] = line.split(None, 3)[3].decode('latin_1') elif sub == 'font': instr['font'] = line.split(None, 1)[1] elif sub == 'fontsize': instr['fontsize'] = float(line.split(None, 1)[1]) elif sub == 'color': instr['color'] = line.split(None, 1)[1] elif sub == 'width': instr['width'] = line.split(None, 1)[1] elif sub == 'hcolor': instr['hcolor'] = line.split(None, 1)[1] elif sub == 'hwidth': instr['hwidth'] = line.split(None, 1)[1] elif sub == 'background': instr['background'] = line.split(None, 1)[1] elif sub == 'border': instr['border'] = line.split(None, 1)[1] elif sub == 'ref': instr['ref'] = line.split(None, 1)[1] elif sub == 'rotate': instr['rotate'] = float(line.split(None, 1)[1]) elif sub == 'xoffset': instr['xoffset'] = int(line.split(None, 1)[1]) elif sub == 'yoffset': instr['yoffset'] = int(line.split(None, 1)[1]) elif sub == 'opaque': if line.split(None, 1)[1].lower() in ('n', 'none'): instr['background'] = 'none' except(IndexError, ValueError): GError(_("Failed to read instruction %s") % instruction) return False instr['where'] = PaperMapCoordinates( mapInstr=map, x=instr['east'], y=instr['north'], paperToMap=False) self.instruction.update(instr) return True class Image(InstructionObject): """Class representing eps instruction - image""" def __init__(self, id, settings): InstructionObject.__init__(self, id=id) self.settings = settings self.type = 'image' # default values self.defaultInstruction = dict( epsfile="", XY=True, where=( 0, 0), unit='inch', east=None, north=None, rotate=None, scale=1) # current values self.instruction = dict(self.defaultInstruction) def __str__(self): self.ChangeRefPoint(toCenter=True) epsfile = self.instruction['epsfile'].replace( os.getenv('GISBASE'), "$GISBASE") instr = "eps %s %s\n" % ( self.instruction['east'], self.instruction['north']) instr += " epsfile %s\n" % epsfile if self.instruction["rotate"]: instr += string.Template( " rotate $rotate\n").substitute(self.instruction) if self.instruction["scale"]: instr += string.Template( " scale $scale\n").substitute(self.instruction) instr += " end" return instr def Read(self, instruction, text, **kwargs): """Read instruction and save information""" mapInstr = kwargs['mapInstruction'] instr = {} for line in text: try: sub = line.split(None, 1)[0] if sub == 'eps': e, n = line.split(None, 3)[1:3] if '%' in e and '%' in n: instr['XY'] = True instr['east'], instr[ 'north'] = self.PercentToReal(e, n) else: instr['XY'] = False instr['east'], instr['north'] = float(e), float(n) elif sub == 'epsfile': epsfile = line.split(None, 1)[1] instr['epsfile'] = epsfile.replace( "$GISBASE", os.getenv("GISBASE")) elif sub == 'rotate': instr['rotate'] = float(line.split(None, 1)[1]) elif sub == 'scale': instr['scale'] = float(line.split(None, 1)[1]) except(IndexError, ValueError): GError(_("Failed to read instruction %s") % instruction) return False if not os.path.exists(instr['epsfile']): GError(_("Failed to read instruction %(inst)s: " "file %(file)s not found.") % {'inst': instruction, 'file': instr['epsfile']}) return False instr['epsfile'] = os.path.abspath(instr['epsfile']) instr['size'] = self.GetImageOrigSize(instr['epsfile']) if 'rotate' in instr: instr['size'] = BBoxAfterRotation( instr['size'][0], instr['size'][1], instr['rotate']) self.instruction.update(instr) self.ChangeRefPoint(toCenter=False) instr['where'] = PaperMapCoordinates( mapInstr=mapInstr, x=self.instruction['east'], y=self.instruction['north'], paperToMap=False) w = self.unitConv.convert( value=instr['size'][0], fromUnit='point', toUnit='inch') h = self.unitConv.convert( value=instr['size'][1], fromUnit='point', toUnit='inch') instr['rect'] = Rect2D( x=float(instr['where'][0]), y=float(instr['where'][1]), width=w * self.instruction['scale'], height=h * self.instruction['scale']) self.instruction.update(instr) return True def ChangeRefPoint(self, toCenter): """Change reference point (left top x center)""" mapInstr = self.settings.FindInstructionByType('map') if not mapInstr: mapInstr = self.settings.FindInstructionByType('initMap') mapId = mapInstr.id if toCenter: center = self.instruction['rect'].GetCentre() ENCenter = PaperMapCoordinates( mapInstr=self.settings[mapId], x=center[0], y=center[1], paperToMap=True) self.instruction['east'], self.instruction['north'] = ENCenter else: x, y = PaperMapCoordinates( mapInstr=self.settings[mapId], x=self.instruction['east'], y=self.instruction['north'], paperToMap=False) w = self.unitConv.convert( value=self.instruction['size'][0], fromUnit='point', toUnit='inch') h = self.unitConv.convert( value=self.instruction['size'][1], fromUnit='point', toUnit='inch') x -= w * self.instruction['scale'] / 2 y -= h * self.instruction['scale'] / 2 e, n = PaperMapCoordinates( mapInstr=self.settings[mapId], x=x, y=y, paperToMap=True) self.instruction['east'], self.instruction['north'] = e, n def GetImageOrigSize(self, imagePath): """Get image size. If eps, size is read from image header. """ fileName = os.path.split(imagePath)[1] # if eps, read info from header if os.path.splitext(fileName)[1].lower() == '.eps': bbInfo = "%%BoundingBox" file = open(imagePath, "r") w = h = 0 while file: line = file.readline() if line.find(bbInfo) == 0: w, h = line.split()[3:5] break file.close() return float(w), float(h) else: # we can use wx.Image img = wx.Image(fileName, type=wx.BITMAP_TYPE_ANY) return img.GetWidth(), img.GetHeight() class NorthArrow(Image): """Class representing eps instruction -- North Arrow""" def __init__(self, id, settings): Image.__init__(self, id=id, settings=settings) self.type = 'northArrow' def __str__(self): self.ChangeRefPoint(toCenter=True) epsfile = self.instruction['epsfile'].replace( os.getenv('GISBASE'), "$GISBASE") instr = "eps %s %s\n" % ( self.instruction['east'], self.instruction['north']) instr += "# north arrow\n" instr += " epsfile %s\n" % epsfile if self.instruction["rotate"]: instr += string.Template( " rotate $rotate\n").substitute(self.instruction) if self.instruction["scale"]: instr += string.Template( " scale $scale\n").substitute(self.instruction) instr += " end" return instr class Point(InstructionObject): """Class representing point instruction""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'point' # default values self.defaultInstruction = dict(symbol=os.path.join('basic', 'x'), color='0:0:0', fcolor='200:200:200', rotate=0, size=10, XY=True, where=(0, 0), unit='inch', east=None, north=None) # current values self.instruction = dict(self.defaultInstruction) def __str__(self): instr = string.Template( "point $east $north\n").substitute(self.instruction) instr += string.Template(" symbol $symbol\n").substitute(self.instruction) instr += string.Template(" color $color\n").substitute(self.instruction) instr += string.Template(" fcolor $fcolor\n").substitute(self.instruction) instr += string.Template(" rotate $rotate\n").substitute(self.instruction) instr += string.Template(" size $size\n").substitute(self.instruction) instr += " end" return instr def Read(self, instruction, text, **kwargs): """Read instruction and save information""" mapInstr = kwargs['mapInstruction'] instr = {} for line in text: try: sub = line.split(None, 1)[0] if sub == 'point': e, n = line.split(None, 3)[1:3] if '%' in e and '%' in n: instr['XY'] = True instr['east'], instr[ 'north'] = self.PercentToReal(e, n) else: instr['XY'] = False instr['east'], instr['north'] = float(e), float(n) elif sub == 'symbol': instr['symbol'] = line.split(None, 1)[1] elif sub == 'rotate': instr['rotate'] = float(line.split(None, 1)[1]) elif sub == 'size': instr['size'] = float(line.split(None, 1)[1]) elif sub == 'color': instr['color'] = line.split(None, 1)[1] elif sub == 'fcolor': instr['fcolor'] = line.split(None, 1)[1] except(IndexError, ValueError): GError(_("Failed to read instruction %s") % instruction) return False self.instruction.update(instr) instr['where'] = PaperMapCoordinates( mapInstr=mapInstr, x=self.instruction['east'], y=self.instruction['north'], paperToMap=False) w = h = self.unitConv.convert( value=instr['size'], fromUnit='point', toUnit='inch') instr['rect'] = Rect2D( x=float(instr['where'][0]) - w / 2, y=float(instr['where'][1] - h / 2), width=w, height=h) self.instruction.update(instr) return True class Line(InstructionObject): """Class representing line instruction""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'line' # default values self.defaultInstruction = dict(color='0:0:0', width=2, where=[wx.Point2D(), wx.Point2D()], east1=None, north1=None, east2=None, north2=None) # current values self.instruction = dict(self.defaultInstruction) def __str__(self): instr = string.Template( "line $east1 $north1 $east2 $north2\n").substitute(self.instruction) instr += string.Template(" color $color\n").substitute(self.instruction) instr += string.Template(" width $width\n").substitute(self.instruction) instr += " end\n" return instr def Read(self, instruction, text, **kwargs): """Read instruction and save information""" mapInstr = kwargs['mapInstruction'] instr = {} for line in text: try: sub = line.split(None, 1)[0] if sub == 'line': e1, n1, e2, n2 = line.split(None, 5)[1:5] if '%' in e1 and '%' in n1 and '%' in e2 and '%' in n2: instr['east1'], instr[ 'north1'] = self.PercentToReal(e1, n1) instr['east2'], instr[ 'north2'] = self.PercentToReal(e2, n2) else: instr['east1'], instr['north1'] = float(e1), float(n1) instr['east2'], instr['north2'] = float(e2), float(n2) elif sub == 'width': instr['width'] = float(line.split(None, 1)[1]) elif sub == 'color': instr['color'] = line.split(None, 1)[1] except(IndexError, ValueError): GError(_("Failed to read instruction %s") % instruction) return False self.instruction.update(instr) e1, n1 = PaperMapCoordinates( mapInstr=mapInstr, x=self.instruction['east1'], y=self.instruction['north1'], paperToMap=False) e2, n2 = PaperMapCoordinates( mapInstr=mapInstr, x=self.instruction['east2'], y=self.instruction['north2'], paperToMap=False) instr['where'] = [wx.Point2D(e1, n1), wx.Point2D(e2, n2)] instr['rect'] = Rect2DPP(instr['where'][0], instr['where'][1]) self.instruction.update(instr) return True class Rectangle(InstructionObject): """Class representing rectangle instruction""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'rectangle' # default values self.defaultInstruction = dict(color='0:0:0', fcolor='none', width=2, east1=None, north1=None, east2=None, north2=None) # current values self.instruction = dict(self.defaultInstruction) def __str__(self): instr = string.Template( "rectangle $east1 $north1 $east2 $north2\n").substitute(self.instruction) instr += string.Template(" color $color\n").substitute(self.instruction) instr += string.Template(" fcolor $fcolor\n").substitute(self.instruction) instr += string.Template(" width $width\n").substitute(self.instruction) instr += " end\n" return instr def Read(self, instruction, text, **kwargs): """Read instruction and save information""" mapInstr = kwargs['mapInstruction'] instr = {} for line in text: try: sub = line.split(None, 1)[0] if sub == 'rectangle': e1, n1, e2, n2 = line.split(None, 5)[1:5] if '%' in e1 and '%' in n1 and '%' in e2 and '%' in n2: instr['east1'], instr[ 'north1'] = self.PercentToReal(e1, n1) instr['east2'], instr[ 'north2'] = self.PercentToReal(e2, n2) else: instr['east1'], instr['north1'] = float(e1), float(n1) instr['east2'], instr['north2'] = float(e2), float(n2) elif sub == 'width': instr['width'] = float(line.split(None, 1)[1]) elif sub == 'color': instr['color'] = line.split(None, 1)[1] elif sub == 'fcolor': instr['fcolor'] = line.split(None, 1)[1] except(IndexError, ValueError): GError(_("Failed to read instruction %s") % instruction) return False self.instruction.update(instr) e1, n1 = PaperMapCoordinates( mapInstr=mapInstr, x=self.instruction['east1'], y=self.instruction['north1'], paperToMap=False) e2, n2 = PaperMapCoordinates( mapInstr=mapInstr, x=self.instruction['east2'], y=self.instruction['north2'], paperToMap=False) instr['rect'] = Rect2DPP(wx.Point2D(e1, n1), wx.Point2D(e2, n2)) self.instruction.update(instr) return True class Scalebar(InstructionObject): """Class representing scalebar instruction""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'scalebar' # default values self.defaultInstruction = dict(unit='inch', where=(1, 1), unitsLength='auto', unitsHeight='inch', length=None, height=0.1, rect=None, fontsize=10, background='y', scalebar='f', segment=4, numbers=1) # current values self.instruction = dict(self.defaultInstruction) def __str__(self): instr = string.Template( "scalebar $scalebar\n").substitute(self.instruction) instr += " where %.3f %.3f\n" % ( self.instruction['where'][0], self.instruction['where'][1]) instr += string.Template( " length $length\n units $unitsLength\n").substitute(self.instruction) instr += string.Template(" height $height\n").substitute(self.instruction) instr += string.Template( " segment $segment\n numbers $numbers\n").substitute(self.instruction) instr += string.Template( " fontsize $fontsize\n background $background\n").substitute( self.instruction) instr += " end" return instr def Read(self, instruction, text, **kwargs): """Read instruction and save information""" scale = kwargs['scale'] instr = {} for line in text: try: if line.startswith('scalebar'): if 'scalebar s' in line: instr['scalebar'] = 's' else: instr['scalebar'] = 'f' elif line.startswith('where'): instr['where'] = list(map(float, line.split()[1:3])) elif line.startswith('length'): instr['length'] = float(line.split()[1]) elif line.startswith('units'): if line.split()[1] in[ 'auto', 'meters', 'kilometers', 'feet', 'miles', 'nautmiles']: instr['unitsLength'] = line.split()[1] elif line.startswith('height'): instr['height'] = float(line.split()[1]) elif line.startswith('fontsize'): instr['fontsize'] = float(line.split()[1]) elif line.startswith('numbers'): instr['numbers'] = int(line.split()[1]) elif line.startswith('segment'): instr['segment'] = int(line.split()[1]) elif line.startswith('background'): if line.split()[1].strip().lower() in ('y', 'yes'): instr['background'] = 'y' elif line.split()[1].strip().lower() in ('n', 'no', 'none'): instr['background'] = 'n' except(IndexError, ValueError): GError(_("Failed to read instruction %s") % instruction) return False self.instruction.update(instr) w, h = self.EstimateSize(scalebarDict=self.instruction, scale=scale) x = self.instruction['where'][0] - w / 2 y = self.instruction['where'][1] - h / 2 self.instruction['rect'] = Rect2D(x, y, w, h) return True def EstimateSize(self, scalebarDict, scale): """Estimate size to draw scalebar""" units = projInfo()['units'] if not units or units not in self.unitConv.getAllUnits(): units = 'meters' if scalebarDict['unitsLength'] != 'auto': length = self.unitConv.convert( value=scalebarDict['length'], fromUnit=scalebarDict['unitsLength'], toUnit='inch') else: length = self.unitConv.convert( value=scalebarDict['length'], fromUnit=units, toUnit='inch') length *= scale length *= 1.1 # for numbers on the edge height = scalebarDict['height'] + 2 * self.unitConv.convert( value=scalebarDict['fontsize'], fromUnit='point', toUnit='inch') return (length, height) class RasterLegend(InstructionObject): """Class representing colortable instruction""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'rasterLegend' # default values self.defaultInstruction = dict(rLegend=False, unit='inch', rasterDefault=True, raster=None, discrete=None, type=None, where=(0, 0), width=None, height=None, cols=1, font="Helvetica", fontsize=10, # color = '0:0:0', tickbar = False, # range = False, min = 0, max = 0, color='black', tickbar='n', range=False, min=0, max=0, nodata='n') # current values self.instruction = dict(self.defaultInstruction) def __str__(self): instr = "colortable y\n" instr += string.Template(" raster $raster\n").substitute(self.instruction) instr += " where %.3f %.3f\n" % ( self.instruction['where'][0], self.instruction['where'][1]) if self.instruction['width']: instr += string.Template( " width $width\n").substitute(self.instruction) instr += string.Template( " discrete $discrete\n").substitute(self.instruction) if self.instruction['discrete'] == 'n': if self.instruction['height']: instr += string.Template( " height $height\n").substitute(self.instruction) instr += string.Template( " tickbar $tickbar\n").substitute(self.instruction) if self.instruction['range']: instr += string.Template( " range $min $max\n").substitute(self.instruction) else: instr += string.Template(" cols $cols\n").substitute(self.instruction) instr += string.Template( " nodata $nodata\n").substitute(self.instruction) instr += string.Template(" font $font\n fontsize $fontsize\n color $color\n")\ .substitute(self.instruction) instr += " end" return instr def Read(self, instruction, text, **kwargs): """Read instruction and save information""" instr = {} instr['rLegend'] = True for line in text: try: if line.startswith('where'): instr['where'] = list(map(float, line.split()[1:3])) elif line.startswith('font '): instr['font'] = line.split()[1] elif line.startswith('fontsize'): instr['fontsize'] = float(line.split()[1]) elif line.startswith('color '): instr['color'] = line.split()[1] elif line.startswith('raster'): instr['raster'] = line.split()[1] elif line.startswith('width'): instr['width'] = float(line.split()[1]) elif line.startswith('height'): instr['height'] = float(line.split()[1]) elif line.startswith('cols'): instr['cols'] = int(line.split()[1]) elif line.startswith('range'): instr['range'] = True instr['min'] = float(line.split()[1]) instr['max'] = float(line.split()[2]) elif line.startswith('nodata'): if line.split()[1].strip().lower() in ('y', 'yes'): instr['nodata'] = 'y' elif line.split()[1].strip().lower() in ('n', 'no', 'none'): instr['nodata'] = 'n' elif line.startswith('tickbar'): if line.split()[1].strip().lower() in ('y', 'yes'): instr['tickbar'] = 'y' elif line.split()[1].strip().lower() in ('n', 'no', 'none'): instr['tickbar'] = 'n' elif line.startswith('discrete'): if line.split()[1].strip().lower() in ('y', 'yes'): instr['discrete'] = 'y' elif line.split()[1].strip().lower() in ('n', 'no', 'none'): instr['discrete'] = 'n' except(IndexError, ValueError): GError(_("Failed to read instruction %s") % instruction) return False if 'raster' in instr: instr['rasterDefault'] = False if 'discrete' not in instr: rasterType = getRasterType(map=instr['raster']) instr['type'] = rasterType if rasterType == 'CELL': instr['discrete'] = 'y' else: instr['discrete'] = 'n' else: instr['rasterDefault'] = True self.instruction.update(instr) # add 'rect' in the end return True def EstimateHeight(self, raster, discrete, fontsize, cols=None, height=None): """Estimate height to draw raster legend""" if discrete == 'n': if height: height = height else: height = self.unitConv.convert(value=fontsize * 10, fromUnit='point', toUnit='inch') if discrete == 'y': if cols: cols = cols else: cols = 1 rinfo = grass.raster_info(raster) if rinfo['datatype'] in ('DCELL', 'FCELL'): minim, maxim = rinfo['min'], rinfo['max'] rows = ceil(maxim / cols) else: cat = grass.read_command('r.category', map=raster, sep=':').strip().split('\n') rows = ceil(float(len(cat)) / cols) height = self.unitConv.convert( value=1.5 * rows * fontsize, fromUnit='point', toUnit='inch') return height def EstimateWidth(self, raster, discrete, fontsize, cols=None, width=None, paperInstr=None): """Estimate size to draw raster legend""" if discrete == 'n': rinfo = grass.raster_info(raster) minim, maxim = rinfo['min'], rinfo['max'] if width: width = width else: width = self.unitConv.convert(value=fontsize * 2, fromUnit='point', toUnit='inch') text = len(max(str(minim), str(maxim), key=len)) textPart = self.unitConv.convert(value=text * fontsize / 2, fromUnit='point', toUnit='inch') width += textPart elif discrete == 'y': if cols: cols = cols else: cols = 1 if width: width = width else: paperWidth = paperInstr[ 'Width'] - paperInstr['Right'] - paperInstr['Left'] width = (paperWidth / cols) * (cols - 1) + 1 return width class VectorLegend(InstructionObject): """Class representing colortable instruction""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'vectorLegend' # default values self.defaultInstruction = dict( vLegend=False, unit='inch', where=( 0, 0), defaultSize=True, width=0.4, cols=1, span=None, font="Helvetica", fontsize=10, border='none') # current values self.instruction = dict(self.defaultInstruction) def __str__(self): instr = "vlegend\n" instr += " where %.3f %.3f\n" % ( self.instruction['where'][0], self.instruction['where'][1]) instr += string.Template( " font $font\n fontsize $fontsize\n").substitute(self.instruction) instr += string.Template( " width $width\n cols $cols\n").substitute(self.instruction) if self.instruction['span']: instr += string.Template(" span $span\n").substitute(self.instruction) instr += string.Template(" border $border\n").substitute(self.instruction) instr += " end" return instr def Read(self, instruction, text, **kwargs): """Read instruction and save information""" instr = {} instr['vLegend'] = True for line in text: try: if line.startswith('where'): instr['where'] = list(map(float, line.split()[1:3])) elif line.startswith('font '): instr['font'] = line.split()[1] elif line.startswith('fontsize'): instr['fontsize'] = float(line.split()[1]) elif line.startswith('width'): instr['width'] = float(line.split()[1]) elif line.startswith('cols'): instr['cols'] = int(line.split()[1]) elif line.startswith('span'): instr['span'] = float(line.split()[1]) elif line.startswith('border'): instr['border'] = line.split()[1] except(IndexError, ValueError): GError(_("Failed to read instruction %s") % instruction) return False self.instruction.update(instr) return True def EstimateSize(self, vectorInstr, fontsize, width=None, cols=None): """Estimate size to draw vector legend""" if width: width = width else: width = fontsize / 24.0 if cols: cols = cols else: cols = 1 vectors = vectorInstr['list'] labels = [vector[4] for vector in vectors if vector[3] != 0] extent = (len(max(labels, key=len)) * fontsize / 2, fontsize) wExtent = self.unitConv.convert( value=extent[0], fromUnit='point', toUnit='inch') hExtent = self.unitConv.convert( value=extent[1], fromUnit='point', toUnit='inch') w = (width + wExtent) * cols h = len(labels) * hExtent / cols h *= 1.1 return (w, h) class Raster(InstructionObject): """Class representing raster instruction""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'raster' # default values self.defaultInstruction = dict(isRaster=False, raster=None) # current values self.instruction = dict(self.defaultInstruction) def __str__(self): instr = string.Template("raster $raster").substitute(self.instruction) return instr def Read(self, instruction, text): """Read instruction and save information""" instr = {} instr['isRaster'] = True try: map = text.split()[1] except IndexError: GError(_("Failed to read instruction %s") % instruction) return False try: info = grass.find_file(map, element='cell') except grass.ScriptError as e: GError(message=e.value) return False instr['raster'] = info['fullname'] self.instruction.update(instr) return True class Vector(InstructionObject): """Class keeps vector layers""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'vector' # default values self.defaultInstruction = dict( list=None) # [vmap, type, id, lpos, label] # current values self.instruction = dict(self.defaultInstruction) def __str__(self): return '' def Read(self, instruction, text, **kwargs): """Read instruction and save information""" instr = {} for line in text: if line.startswith('vpoints') or line.startswith( 'vlines') or line.startswith('vareas'): # subtype if line.startswith('vpoints'): subType = 'points' elif line.startswith('vlines'): subType = 'lines' elif line.startswith('vareas'): subType = 'areas' # name of vector map vmap = line.split()[1] try: info = grass.find_file(vmap, element='vector') except grass.ScriptError as e: GError(message=e.value) return False vmap = info['fullname'] # id id = kwargs['id'] # lpos lpos = kwargs['vectorMapNumber'] # label label = '('.join(vmap.split('@')) + ')' break instr = [vmap, subType, id, lpos, label] if not self.instruction['list']: self.instruction['list'] = [] self.instruction['list'].append(instr) return True class VProperties(InstructionObject): """Class represents instructions vareas, vlines, vpoints""" def __init__(self, id, subType): InstructionObject.__init__(self, id=id) self.type = 'vProperties' self.subType = subType # default values if self.subType == 'points': dd = dict( subType='points', name=None, type='point or centroid', connection=False, layer='1', masked='n', color='0:0:0', width=1, fcolor='255:0:0', rgbcolumn=None, symbol=os.path.join( 'basic', 'x'), eps=None, size=5, sizecolumn=None, scale=None, rotation=False, rotate=0, rotatecolumn=None, label=None, lpos=None) elif self.subType == 'lines': dd = dict( subType='lines', name=None, type='line or boundary', connection=False, layer='1', masked='n', color='0:0:0', hwidth=1, hcolor='none', rgbcolumn=None, width=1, cwidth=None, style='solid', linecap='butt', label=None, lpos=None) else: # areas dd = dict(subType='areas', name=None, connection=False, layer='1', masked='n', color='0:0:0', width=1, fcolor='none', rgbcolumn=None, pat=None, pwidth=1, scale=1, label=None, lpos=None) self.defaultInstruction = dd # current values self.instruction = dict(self.defaultInstruction) def __str__(self): dic = self.instruction vInstruction = string.Template("v$subType $name\n").substitute(dic) # data selection if self.subType in ('points', 'lines'): vInstruction += string.Template(" type $type\n").substitute(dic) if dic['connection']: vInstruction += string.Template( " layer $layer\n").substitute(dic) if 'cats' in dic: vInstruction += string.Template( " cats $cats\n").substitute(dic) elif 'where' in dic: vInstruction += string.Template( " where $where\n").substitute(dic) vInstruction += string.Template(" masked $masked\n").substitute(dic) # colors vInstruction += string.Template(" color $color\n").substitute(dic) if self.subType in ('points', 'areas'): if dic['color'] != 'none': vInstruction += string.Template( " width $width\n").substitute(dic) if dic['rgbcolumn']: vInstruction += string.Template( " rgbcolumn $rgbcolumn\n").substitute(dic) vInstruction += string.Template( " fcolor $fcolor\n").substitute(dic) else: if dic['rgbcolumn']: vInstruction += string.Template( " rgbcolumn $rgbcolumn\n").substitute(dic) elif dic['hcolor'] != 'none': vInstruction += string.Template( " hwidth $hwidth\n").substitute(dic) vInstruction += string.Template( " hcolor $hcolor\n").substitute(dic) # size and style if self.subType == 'points': if not dic['eps']: vInstruction += string.Template( " symbol $symbol\n").substitute(dic) else: # eps vInstruction += string.Template( " eps $eps\n").substitute(dic) if dic['size']: vInstruction += string.Template( " size $size\n").substitute(dic) else: # sizecolumn vInstruction += string.Template( " sizecolumn $sizecolumn\n").substitute(dic) vInstruction += string.Template( " scale $scale\n").substitute(dic) if dic['rotation']: if dic['rotate'] is not None: vInstruction += string.Template( " rotate $rotate\n").substitute(dic) else: vInstruction += string.Template( " rotatecolumn $rotatecolumn\n").substitute(dic) if self.subType == 'areas': if dic['pat'] is not None: patternFile = dic['pat'].replace( os.getenv("GISBASE"), "$GISBASE") vInstruction += " pat %s\n" % patternFile vInstruction += string.Template( " pwidth $pwidth\n").substitute(dic) vInstruction += string.Template( " scale $scale\n").substitute(dic) if self.subType == 'lines': if dic['width'] is not None: vInstruction += string.Template( " width $width\n").substitute(dic) else: vInstruction += string.Template( " cwidth $cwidth\n").substitute(dic) vInstruction += string.Template( " style $style\n").substitute(dic) vInstruction += string.Template( " linecap $linecap\n").substitute(dic) #position and label in vlegend vInstruction += string.Template( " label $label\n lpos $lpos\n").substitute(dic) vInstruction += " end" try: vInstruction = vInstruction.encode('Latin_1') except UnicodeEncodeError as err: try: pos = str(err).split('position')[1].split(':')[0].strip() except IndexError: pos = '' if pos: message = _("Characters on position %s are not supported " "by ISO-8859-1 (Latin 1) encoding " "which is required by module ps.map.") % pos else: message = _("Not all characters are supported " "by ISO-8859-1 (Latin 1) encoding " "which is required by module ps.map.") GMessage(message=message) return '' return vInstruction def Read(self, instruction, text, **kwargs): """Read instruction and save information""" instr = {} try: info = grass.find_file(name=text[0].split()[1], element='vector') except grass.ScriptError as e: GError(message=e.value) return False instr['name'] = info['fullname'] # connection instr['connection'] = True self.mapDBInfo = VectorDBInfo(instr['name']) self.layers = self.mapDBInfo.layers.keys() if not self.layers: instr['connection'] = False # points if text[0].startswith('vpoints'): for line in text[1:]: if line.startswith('type'): tp = [] if line.find('point') != -1: tp.append('point') if line.find('centroid') != -1: tp.append('centroid') instr['type'] = ' or '.join(tp) elif line.startswith('fcolor'): instr['fcolor'] = line.split()[1] elif line.startswith('rgbcolumn'): instr['rgbcolumn'] = line.split()[1] elif line.startswith('symbol'): instr['symbol'] = line.split()[1] elif line.startswith('eps'): instr['eps'] = line.split()[1] elif line.startswith('size '): instr['size'] = line.split()[1] elif line.startswith('sizecolumn'): instr['size'] = None instr['sizecolumn'] = line.split()[1] elif line.startswith('scale '): instr['scale'] = float(line.split()[1]) elif line.startswith('rotate '): instr['rotation'] = True instr['rotate'] = line.split()[1] elif line.startswith('rotatecolumn'): instr['rotatecolumn'] = line.split()[1] instr['rotation'] = True instr['rotate'] = None # lines elif text[0].startswith('vlines'): for line in text[1:]: if line.startswith('type'): tp = [] if line.find('line') != -1: tp.append('line') if line.find('boundary') != -1: tp.append('boundary') instr['type'] = ' or '.join(tp) elif line.startswith('hwidth'): instr['hwidth'] = float(line.split()[1]) elif line.startswith('hcolor'): instr['hcolor'] = line.split()[1] elif line.startswith('rgbcolumn'): instr['rgbcolumn'] = line.split()[1] elif line.startswith('cwidth'): instr['cwidth'] = float(line.split()[1]) instr['width'] = None elif line.startswith('style'): instr['style'] = line.split()[1] elif line.startswith('linecap'): instr['linecap'] = line.split()[1] elif text[0].startswith('vareas'): for line in text[1:]: if line.startswith('fcolor'): instr['fcolor'] = line.split()[1] elif line.startswith('pat'): patternFile = line.split()[1] instr['pat'] = patternFile.replace( "$GISBASE", os.getenv("GISBASE")) elif line.startswith('pwidth'): instr['pwidth'] = float(line.split()[1]) elif line.startswith('scale'): instr['scale'] = float(line.split()[1]) # same properties for all for line in text[1:]: if line.startswith('lpos'): instr['lpos'] = int(line.split()[1]) elif line.startswith('label'): instr['label'] = line.split(None, 1)[1].decode('latin_1') elif line.startswith('layer'): instr['layer'] = line.split()[1] elif line.startswith('masked'): if line.split()[1].lower() in ('y', 'yes'): instr['masked'] = 'y' else: instr['masked'] = 'n' elif line.startswith('color'): instr['color'] = line.split()[1] elif line.startswith('rgbcolumn'): instr['rgbcolumn'] = line.split()[1] elif line.startswith('width'): instr['width'] = float(line.split()[1]) if 'label' not in instr: instr['label'] = '('.join(instr['name'].split('@')) + ')' if 'lpos' not in instr: instr['lpos'] = kwargs['vectorMapNumber'] self.instruction.update(instr) return True class Labels(InstructionObject): """Class representing labels instruction""" def __init__(self, id): InstructionObject.__init__(self, id=id) self.type = 'labels' # default values self.defaultInstruction = dict(labels=[]) # current values self.instruction = dict(self.defaultInstruction) def __str__(self): instr = '' for label in self.instruction['labels']: instr += "labels %s\n" % label instr += "end\n" return instr def Read(self, instruction, text, **kwargs): """Read instruction and save information""" for line in text: try: if line.startswith('labels'): labels = line.split(None, 1)[1] self.instruction['labels'].append(labels) except(IndexError, ValueError): GError(_("Failed to read instruction %s") % instruction) return False return True