""" @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 from io import open import wx import grass.script as grass from grass.script.task import cmdlist_to_tuple from core.gcmd import GError, GMessage, GWarning from core.utils import GetCmdString from dbmgr.vinfo import VectorDBInfo from gui_core.wrap import NewId as wxNewId from psmap.utils import * def NewId(): return int(wxNewId()) class Instruction: """Class which represents instruction file""" def __init__(self, parent, objectsToDraw, env): self.parent = parent self.objectsToDraw = objectsToDraw # here are kept objects like mapinfo, rasterlegend, etc. self.instruction = list() self.env = env 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, labels too vektor = self.FindInstructionByType("vector", list=True) vProperties = self.FindInstructionByType("vProperties", list=True) raster = self.FindInstructionByType("raster", list=True) labels = self.FindInstructionByType("labels", list=True) for item in vektor + vProperties + raster + labels: 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", "labels", ): 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, encoding="Latin_1", errors="ignore") 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(env=self.env) map["center"] = (region["n"] + region["s"]) / 2, (region["w"] + region["e"]) / 2 mapRect = GetMapBounds( self.filename, portrait=(orientation == "Portrait"), env=self.env ) 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, env=self.env ) # 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"] = 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(NewId(), env=self.env) 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 = NewId() # !vProperties expect subtype if i == "vProperties": id = kwargs["id"] newInstr = myInstrDict[i]( id, subType=instruction[1:], env=self.env, ) 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, env=self.env) else: newInstr = myInstrDict[i](id, env=self.env) 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(NewId(), env=self.env) 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 region = grass.region(env=None) cmd = ["g.region", region] cmdString = GetCmdString(cmd).replace("g.region", "") GMessage( _("Instruction file will be loaded with following region: %s\n") % cmdString ) try: self.env["GRASS_REGION"] = grass.region_env(env=self.env, **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, env): self.id = id self.env = env # 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(env=self.env) 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, env): InstructionObject.__init__(self, id=id, env=env) 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, env): InstructionObject.__init__(self, id=id, env=env) 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(env=self.env) 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, env): InstructionObject.__init__(self, id=id, env=env) 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, env): InstructionObject.__init__(self, id=id, env=env) 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, env): InstructionObject.__init__(self, id=id, env=env) 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 = "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" 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] 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, env=self.env, ) self.instruction.update(instr) return True class Image(InstructionObject): """Class representing eps instruction - image""" def __init__(self, id, settings, env): InstructionObject.__init__(self, id=id, env=env) 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, env=self.env, ) 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, env=self.env, ) 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, env=self.env, ) 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, env=self.env ) 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, env): Image.__init__(self, id=id, settings=settings, env=env) 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, env): InstructionObject.__init__(self, id=id, env=env) 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, env=self.env, ) 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, env): InstructionObject.__init__(self, id=id, env=env) 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, env=self.env, ) e2, n2 = PaperMapCoordinates( mapInstr=mapInstr, x=self.instruction["east2"], y=self.instruction["north2"], paperToMap=False, env=self.env, ) 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, env): InstructionObject.__init__(self, id=id, env=env) 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, env=self.env, ) e2, n2 = PaperMapCoordinates( mapInstr=mapInstr, x=self.instruction["east2"], y=self.instruction["north2"], paperToMap=False, env=self.env, ) 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, env): InstructionObject.__init__(self, id=id, env=env) 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, env): InstructionObject.__init__(self, id=id, env=env) 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, env): InstructionObject.__init__(self, id=id, env=env) 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, env): InstructionObject.__init__(self, id=id, env=env) 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, env): InstructionObject.__init__(self, id=id, env=env) 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, env): InstructionObject.__init__(self, id=id, env=env) 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" 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] 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, env): InstructionObject.__init__(self, id=id, env=env) 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