instructions.py 81 KB

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