instructions.py 82 KB

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