instructions.py 81 KB

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