instructions.py 80 KB

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