instructions.py 82 KB

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