instructions.py 82 KB

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