source: grass/tags/release_20080321_grass_6_3_0RC6/gui/wxpython/gui_modules/render.py

Last change on this file was 30646, checked in by martinl, 16 years ago

wxGUI: synchronized with trunk (for RC6)

File size: 30.8 KB
Line 
1"""
2@package render
3
4Rendering map layers into image
5
6Classes:
7 - MapLayer
8 - Map
9
10C) 2006-2008 by the GRASS Development Team
11This program is free software under the GNU General Public
12License (>=v2). Read the file COPYING that comes with GRASS
13for details.
14
15@author Michael Barton, Jachym Cepicky, Martin Landa
16
17@date 2006-2008
18"""
19
20import os
21import sys
22import glob
23import math
24try:
25 import subprocess
26except:
27 compatPath = os.path.join(globalvar.ETCWXDIR, "compat")
28 sys.path.append(compatPath)
29 import subprocess
30
31import wx
32
33import globalvar
34import utils
35import gcmd
36from debug import Debug as Debug
37
38#
39# use g.pnmcomp for creating image composition or
40# wxPython functionality
41#
42USE_GPNMCOMP = True
43
44class MapLayer(object):
45 """Stores information about map layers or overlays to be displayed"""
46 def __init__(self, type, cmd, name=None,
47 active=True, hidden=False, opacity=1.0):
48 """
49 @param type layer type (raster, vector, overlay, command, etc.)
50 @param cmd GRASS command for rendering layer, given as list, e.g. ['d.rast', 'map=elevation@PERMANENT']
51 @param name layer name, e.g. 'elevation@PERMANENT'
52 @param active layer is active, will be rendered only if True
53 @param hidden layer is hidden, won't be listed in Layer Manager if True
54 @param opacity layer opacity <0;1>
55 """
56 self.type = type
57 self.name = name
58 self.cmdlist = cmd
59
60 self.active = active
61 self.hidden = hidden
62 self.opacity = opacity
63
64 Debug.msg (3, "MapLayer.__init__(): type=%s, cmd='%s', name=%s, " \
65 "active=%d, opacity=%d, hidden=%d" % \
66 (self.type, self.GetCmd(string=True), self.name, self.active,
67 self.opacity, self.hidden))
68
69 # generated file for layer
70 gtemp = utils.GetTempfile()
71 self.maskfile = gtemp + ".pgm"
72 if self.type == "overlay":
73 self.mapfile = gtemp + ".png"
74 else:
75 self.mapfile = gtemp + ".ppm"
76
77 def __del__(self):
78 Debug.msg (3, "MapLayer.__del__(): layer=%s, cmd='%s'" %
79 (self.name, self.GetCmd(string=True)))
80
81 def Render(self):
82 """Render map layer to image
83
84 @return name of file with rendered image or None
85 """
86 if len(self.cmdlist) == 0:
87 return
88
89 Debug.msg (3, "MapLayer.Render(): type=%s" % \
90 (self.type))
91
92 #
93 # to be sure, set temporary file with layer and mask
94 #
95 gtemp = utils.GetTempfile()
96 self.maskfile = gtemp + ".pgm"
97 if self.type == 'overlay':
98 self.mapfile = gtemp + ".png"
99 else:
100 self.mapfile = gtemp + ".ppm"
101
102 #
103 # prepare command for each layer
104 #
105 layertypes = ['raster', 'rgb', 'his', 'shaded', 'rastarrow', 'rastnum',
106 'vector','thememap','themechart',
107 'grid', 'geodesic', 'rhumb', 'labels',
108 'command',
109 'overlay']
110
111 if self.type not in layertypes:
112 raise gcmd.GStdError(_("<%(name)s>: layer type <%(type)s> is not supported yet.") % \
113 {'type' : self.type, 'name' : self.name})
114
115 #
116 # start monitor
117 #
118 os.environ["GRASS_PNGFILE"] = self.mapfile
119
120 #
121 # execute command
122 #
123 try:
124 runcmd = gcmd.Command(cmd=self.cmdlist + ['--q'],
125 stderr=None)
126 except gcmd.CmdError, e:
127 print e
128
129 if runcmd.returncode != 0:
130 self.mapfile = None
131 self.maskfile = None
132 return None
133
134 #
135 # stop monitor
136 #
137 os.unsetenv("GRASS_PNGFILE")
138
139 return self.mapfile
140
141 def GetMapset(self):
142 """
143 @return mapset name of the layer
144 """
145 if not self.name:
146 return ''
147
148 try:
149 return self.name.split('@')[1]
150 except IndexError:
151 return self.name
152
153 def GetCmd(self, string=False):
154 """
155 @param string get command as string if True otherwise list
156
157 @return command list/string
158 """
159 if string:
160 return ' '.join(self.cmdlist)
161 else:
162 return self.cmdlist
163
164 def GetOpacity(self, float=False):
165 """
166 Get opacity level
167 @param float get opacity level in <0,1> otherwise <0,100>
168
169 @return opacity level
170 """
171 if float:
172 return self.opacity
173
174 return int (self.opacity * 100)
175
176class Map(object):
177 """
178 Map composition (stack of map layers)
179 """
180 def __init__(self):
181 #
182 # region/extent settigns
183 #
184 self.wind = {} # WIND settings (wind file)
185 self.region = {} # region settings (g.region)
186 self.width = 640 # map width
187 self.height = 480 # map height
188
189 #
190 # list of layers
191 #
192 self.layers = [] # stack of available GRASS layer
193
194 self.overlays = [] # stack of available overlays
195 self.ovlookup = {} # lookup dictionary for overlay items and overlays
196
197 #
198 # environment settings
199 #
200 self.env = {} # enviroment variables, like MAPSET, LOCATION_NAME, etc.
201 self.verbosity = 0 # --q
202
203 #
204 # generated file for rendering the map
205 #
206 self.mapfile = utils.GetTempfile()
207
208 # setting some initial env. variables
209 self.InitGisEnv() # g.gisenv
210 self.InitRegion()
211 os.environ["GRASS_TRANSPARENT"] = "TRUE"
212 os.environ["GRASS_BACKGROUNDCOLOR"] = "ffffff"
213 os.environ["GRASS_HEIGHT"] = str(self.height)
214 os.environ["GRASS_WIDTH"] = str(self.width)
215 os.environ["GRASS_MESSAGE_FORMAT"] = "gui"
216 os.environ["GRASS_PNG_AUTO_WRITE"] = "TRUE"
217 os.environ["GRASS_TRUECOLOR"] = "TRUE"
218 os.environ["GRASS_COMPRESSION"] = "0"
219 os.environ["GRASS_VERBOSE"] = str(self.verbosity)
220
221 def InitRegion(self):
222 """
223 Initialize current region settings.
224
225 Set up 'self.region' using g.region command and
226 self.wind according to the wind file.
227
228 Adjust self.region based on map window size.
229 """
230
231 #
232 # setting region ('g.region -upg')
233 #
234 self.region = self.GetRegion()
235
236 #
237 # read WIND file
238 #
239 self.GetWindow()
240
241 #
242 # setting resolution
243 #
244 self.SetRegion()
245
246 def InitGisEnv(self):
247 """
248 Stores GRASS variables (g.gisenv) to self.env variable
249 """
250
251 if not os.getenv("GISBASE"):
252 print >> sys.stderr, _("GISBASE not set. You must be in GRASS GIS to run this program.")
253 sys.exit(1)
254
255 gisenvCmd = gcmd.Command(["g.gisenv"])
256
257 for line in gisenvCmd.ReadStdOutput():
258 line = line.strip()
259 key, val = line.split("=")
260 val = val.replace(";","")
261 val = val.replace("'","")
262 self.env[key] = val
263
264 def GetWindow(self):
265 """Read WIND file and set up self.wind dictionary"""
266 # FIXME: duplicated region WIND == g.region (at least some values)
267 windfile = os.path.join (self.env['GISDBASE'],
268 self.env['LOCATION_NAME'],
269 self.env['MAPSET'],
270 "WIND")
271 try:
272 windfile = open (windfile, "r")
273 except StandardError, e:
274 sys.stderr.write("%s %<s>: %s" % (_("Unable to open file"), windfile, e))
275 sys.exit(1)
276
277 for line in windfile.readlines():
278 line = line.strip()
279 key, value = line.split(":",1)
280 key = key.strip()
281 value = value.strip()
282 self.wind[key] = value
283
284 windfile.close()
285
286 return self.wind
287
288 def __adjustRegion(self):
289 """
290 Adjusts display resolution to match monitor size in pixels.
291 Maintains constant display resolution, not related to computational
292 region. Do NOT use the display resolution to set computational
293 resolution. Set computational resolution through g.region.
294 """
295
296 mapwidth = abs(self.region["e"] - self.region["w"])
297 mapheight = abs(self.region['n'] - self.region['s'])
298
299 self.region["nsres"] = mapheight / self.height
300 self.region["ewres"] = mapwidth / self.width
301 self.region['rows'] = round(mapheight / self.region["nsres"])
302 self.region['cols'] = round(mapwidth / self.region["ewres"])
303 self.region['cells'] = self.region['rows'] * self.region['cols']
304
305 Debug.msg (3, "Map.__adjustRegion(): %s" % self.region)
306
307 return self.region
308
309 def AlignResolution(self):
310 """
311 Sets display extents to even multiple of
312 current resolution defined in WIND file from SW corner.
313 This must be done manually as using the -a flag
314 can produce incorrect extents.
315 """
316
317 # new values to use for saving to region file
318 new = {}
319 n = s = e = w = 0.0
320 nwres = ewres = 0.0
321
322 # Get current values for region and display
323 nsres = self.GetRegion()['nsres']
324 ewres = self.GetRegion()['ewres']
325
326 n = float(self.region['n'])
327 s = float(self.region['s'])
328 e = float(self.region['e'])
329 w = float(self.region['w'])
330
331 # Calculate rows, columns, and extents
332 new['rows'] = math.fabs(round((n-s)/nsres))
333 new['cols'] = math.fabs(round((e-w)/ewres))
334
335 # Calculate new extents
336 new['s'] = nsres * round(s/nsres)
337 new['w'] = ewres * round(w/ewres)
338 new['n'] = new['s'] + (new['rows'] * nsres)
339 new['e'] = new['w'] + (new['cols'] * ewres)
340
341 return new
342
343 def AlignExtentFromDisplay(self):
344 """Sets display extents (n,s,e,w) to even multiple of
345 current display resolution from center point"""
346
347 # calculate new bounding box based on center of display
348 if self.region["ewres"] > self.region["nsres"]:
349 res = self.region["ewres"]
350 else:
351 res = self.region["nsres"]
352
353 Debug.msg(3, "Map.AlignExtentFromDisplay(): width=%d, height=%d, res=%f, center=%f,%f" % \
354 (self.width, self.height, res, self.region['center_easting'],
355 self.region['center_northing']))
356
357 ew = (self.width / 2) * res
358 ns = (self.height / 2) * res
359
360 self.region['n'] = self.region['center_northing'] + ns
361 self.region['s'] = self.region['center_northing'] - ns
362 self.region['e'] = self.region['center_easting'] + ew
363 self.region['w'] = self.region['center_easting'] - ew
364
365 def ChangeMapSize(self, (width, height)):
366 """Change size of rendered map.
367
368 @param width,height map size
369
370 @return True on success
371 @return False on failure
372 """
373 try:
374 self.width = int(width)
375 self.height = int(height)
376 Debug.msg(2, "Map.ChangeMapSize(): width=%d, height=%d" % \
377 (self.width, self.height))
378 return True
379 except:
380 self.width = 640
381 self.height = 480
382 return False
383
384 def GetRegion(self, rast=None, vect=None,
385 n=None, s=None, e=None, w=None):
386 """
387 Get region settings
388
389 Optionaly raster or vector map layer can be given.
390
391 @param rast raster name or None
392 @param vect vector name or None
393
394 @return region settings as directory, e.g. {
395 "n":"4928010", "s":"4913700", "w":"589980",...}
396 """
397
398 region = {}
399
400 tmpreg = os.getenv("GRASS_REGION")
401 os.unsetenv("GRASS_REGION")
402
403 # do not update & shell style output
404 cmdList = ["g.region", "-u", "-g", "-p", "-c"]
405
406 if n:
407 cmdList.append('n=%s' % n)
408 if s:
409 cmdList.append('s=%s' % s)
410 if e:
411 cmdList.append('e=%s' % e)
412 if w:
413 cmdList.append('w=%s' % w)
414
415 if rast:
416 cmdList.append('rast=%s' % rast)
417 if vect:
418 cmdList.append('vect=%s' % vect)
419
420 try:
421 cmdRegion = gcmd.Command(cmdList)
422 except gcmd.CmdError, e:
423 if rast:
424 e.message = _("Unable to zoom to raster map <%s>.") % rast + \
425 '%s%s' % (os.linesep, os.linesep) + e.message
426 elif vect:
427 e.message = _("Unable to zoom to vector map <%s>.") % vect + \
428 '%s%s' % (os.linesep, os.linesep) + e.message
429
430 print e
431 return self.region
432
433 for reg in cmdRegion.ReadStdOutput():
434 key, val = reg.split("=", 1)
435 try:
436 region[key] = float(val)
437 except ValueError:
438 region[key] = val
439
440 # restore region
441 if tmpreg:
442 os.environ["GRASS_REGION"] = tmpreg
443
444 Debug.msg (3, "Map.GetRegion(): %s" % region)
445
446 return region
447
448 def SetRegion(self, windres=False):
449 """
450 Render string for GRASS_REGION env. variable, so that the images will be rendered
451 from desired zoom level.
452
453 @param windres If windres set to True, uses resolution from
454 WIND file rather than display (for modules that require set
455 resolution like d.rast.num)
456
457 @return String usable for GRASS_REGION variable or None
458 """
459 grass_region = ""
460
461 # adjust region settigns to match monitor
462 self.region = self.__adjustRegion()
463
464 # newextents = self.AlignResolution()
465 # self.region['n'] = newextents['n']
466 # self.region['s'] = newextents['s']
467 # self.region['e'] = newextents['e']
468 # self.region['w'] = newextents['w']
469
470 # read values from wind file
471 try:
472 for key in self.wind.keys():
473 if key == 'north':
474 grass_region += "north: %s; " % \
475 (self.region['n'])
476 continue
477 elif key == "south":
478 grass_region += "south: %s; " % \
479 (self.region['s'])
480 continue
481 elif key == "east":
482 grass_region += "east: %s; " % \
483 (self.region['e'])
484 continue
485 elif key == "west":
486 grass_region += "west: %s; " % \
487 (self.region['w'])
488 continue
489 elif key == "e-w resol":
490 grass_region += "e-w resol: %f; " % \
491 (self.region['ewres'])
492 continue
493 elif key == "n-s resol":
494 grass_region += "n-s resol: %f; " % \
495 (self.region['nsres'])
496 continue
497 elif key == "cols":
498 grass_region += 'cols: %d; ' % \
499 (self.width)
500 continue
501 elif key == "rows":
502 grass_region += 'rows: %d; ' % \
503 (self.height)
504 continue
505 else:
506 grass_region += key + ": " + self.wind[key] + "; "
507
508 Debug.msg (3, "Map.SetRegion(): %s" % grass_region)
509
510 return grass_region
511
512 except:
513 return None
514
515 def ProjInfo(self):
516 """
517 Return region projection and map units information
518 """
519
520 projinfo = {}
521
522 p = gcmd.Command(['g.proj', '-p'])
523
524 if p.returncode == 0:
525 for line in p.ReadStdOutput():
526 if ':' in line:
527 key,val = line.split(':')
528 key = key.strip()
529 val = val.strip()
530 projinfo[key] = val
531 elif "XY location (unprojected)" in line:
532 projinfo['proj'] = "xy"
533 return projinfo
534 else:
535 return None
536
537 def GetListOfLayers(self, l_type=None, l_mapset=None, l_name=None,
538 l_active=None, l_hidden=None):
539 """
540 Returns list of layers of selected properties or list of all
541 layers.
542
543 @param l_type layer type, e.g. raster/vector/wms/overlay
544 @param l_mapset all layers from given mapset
545 @param l_name all layers with given name
546 @param l_active only layers with 'active' attribute set to True or False
547 @param l_hidden only layers with 'hidden' attribute set to True or False
548
549 @return list of selected layers
550 """
551
552 selected = []
553
554 # ["raster", "vector", "wms", ... ]
555 for layer in self.layers + self.overlays:
556 # specified type only
557 if l_type != None and layer.type != l_type:
558 continue
559
560 # mapset
561 if l_mapset != None and layer.GetMapset() != l_mapset:
562 continue
563
564 # name
565 if l_name != None and layer.name != l_name:
566 continue
567
568 # hidden and active layers
569 if l_active != None and \
570 l_hidden != None:
571 if layer.active == l_active and \
572 layer.hidden == l_hidden:
573 selected.append(layer)
574
575 # active layers
576 elif l_active != None:
577 if layer.active == l_active:
578 selected.append(layer)
579
580 # hidden layers
581 elif l_hidden != None:
582 if layer.hidden == l_hidden:
583 selected.append(layer)
584
585 # all layers
586 else:
587 selected.append(layer)
588
589 Debug.msg (3, "Map.GetListOfLayers(): numberof=%d" % len(selected))
590
591 return selected
592
593 def Render(self, force=False, mapWindow=None):
594 """
595 Creates final image composite
596
597 This function can conditionaly use high-level tools, which
598 should be avaliable in wxPython library
599
600 @param force force rendering
601 @param reference for MapFrame instance (for progress bar)
602
603 @return name of file with rendered image or None
604 """
605
606 maps = []
607 masks =[]
608 opacities = []
609
610 tmp_region = os.getenv("GRASS_REGION")
611 os.environ["GRASS_REGION"] = self.SetRegion()
612 os.environ["GRASS_WIDTH"] = str(self.width)
613 os.environ["GRASS_HEIGHT"] = str(self.height)
614
615 # render map layers
616 for layer in self.layers + self.overlays:
617 # skip if not active
618 if layer == None or layer.active == False:
619 continue
620
621 # render if there is no mapfile
622 if layer.mapfile == None:
623 layer.Render()
624
625 # process bar
626 if mapWindow is not None:
627 mapWindow.onRenderCounter += 1
628
629 wx.Yield()
630 # redraw layer content
631 if force:
632 if not layer.Render():
633 continue
634
635 # add image to compositing list
636 if layer.type != "overlay":
637 maps.append(layer.mapfile)
638 masks.append(layer.maskfile)
639 opacities.append(str(layer.opacity))
640
641 Debug.msg (3, "Map.Render() type=%s, layer=%s " % (layer.type, layer.name))
642
643 # ugly hack for MSYS
644 if not subprocess.mswindows:
645 mapstr = ",".join(maps)
646 maskstr = ",".join(masks)
647 mapoutstr = self.mapfile
648 else:
649 mapstr = ""
650 for item in maps:
651 mapstr += item.replace('\\', '/')
652 mapstr = mapstr.rstrip(',')
653 maskstr = ""
654 for item in masks:
655 maskstr += item.replace('\\', '/')
656 maskstr = maskstr.rstrip(',')
657 mapoutstr = self.mapfile.replace('\\', '/')
658
659 compstring = "g.pnmcomp" + globalvar.EXT_BIN + \
660 " in=" + mapstr + \
661 " mask=" + maskstr + \
662 " opacity=" + ",".join(opacities)+ \
663 " background=255:255:255" + \
664 " width=" + str(self.width) + \
665 " height=" + str(self.height) + \
666 " output=" + mapoutstr
667
668 # compose command
669 complist = ["g.pnmcomp",
670 "in=%s" % ",".join(maps),
671 "mask=%s" % ",".join(masks),
672 "opacity=%s" % ",".join(opacities),
673 "background=255:255:255",
674 "width=%s" % str(self.width),
675 "height=%s" % str(self.height),
676 "output=%s" % self.mapfile]
677
678
679 # render overlays
680
681 os.unsetenv("GRASS_REGION")
682
683 if tmp_region:
684 os.environ["GRASS_REGION"] = tmp_region
685
686 # run g.pngcomp to get composite image
687 try:
688 gcmd.Command(complist)
689 # os.system(compstring)
690 except gcmd.CmdError, e:
691 print e
692 return None
693
694 Debug.msg (2, "Map.Render() force=%s file=%s" % (force, self.mapfile))
695
696 return self.mapfile
697
698 def AddLayer(self, type, command, name=None,
699 l_active=True, l_hidden=False, l_opacity=1.0, l_render=False):
700 """
701 Adds generic display command layer to list of layers
702
703 @param item reference to item in layer tree
704 @param type layer type
705 @param name layer name
706 @param cmd GRASS command to render layer
707 @param l_active checked/not checked for display in layer tree
708 @param l_hidden not used here
709 @param l_opacity opacity leve range from 0(transparent)-1(not transparent)
710 @param l_render render an image if False
711
712 @return new layer on success
713 @return None on failure
714
715 """
716 # l_opacity must be <0;1>
717 if l_opacity < 0: l_opacity = 0
718 elif l_opacity > 1: l_opacity = 1
719
720 layer = MapLayer(type=type, name=name, cmd=command,
721 active=l_active, hidden=l_hidden, opacity=l_opacity)
722
723 # add maplayer to the list of layers
724 self.layers.append(layer)
725
726 Debug.msg (3, "Map.AddLayer(): layer=%s" % layer.name)
727 if l_render:
728 if not layer.Render():
729 raise gcmd.GStdError(_("Unable to render map layer <%s>.") % (name))
730
731 return self.layers[-1]
732
733 def DeleteLayer(self, layer):
734 """
735 Removes layer from list of layers,
736 defined by reference to MapLayer instance
737
738 Returns:
739 Removed layer on success or None
740 """
741
742 Debug.msg (3, "Map.DeleteLayer(): name=%s" % layer.name)
743 if layer in self.layers:
744 if layer.mapfile:
745 base = os.path.split(layer.mapfile)[0]
746 mapfile = os.path.split(layer.mapfile)[1]
747 tempbase = mapfile.split('.')[0]
748 basefile = os.path.join(base,tempbase)+r'.*'
749 for f in glob.glob(basefile):
750 os.remove(f)
751 self.layers.remove(layer)
752 return layer
753
754 return None
755
756 def ReorderLayers(self, layerList):
757 """
758 Make a new reordered list to match reordered
759 layer tree - for drag and drop
760 """
761 self.layers = layerList
762
763 layerNameList = ""
764 for layer in self.layers:
765 if layer.name:
766 layerNameList += layer.name + ','
767 Debug.msg (4, "Map.ReoderLayers(): layers=%s" % \
768 (layerNameList))
769
770 def ChangeLayer(self, layer, type, command, name=None,
771 l_active=True, l_hidden=False, l_opacity=1, l_render=False):
772 """
773 Change the command and other other options for a layer
774 """
775
776 # l_opacity must be <0;1>
777 if l_opacity < 0: l_opacity = 0
778 elif l_opacity > 1: l_opacity = 1
779
780 Debug.msg (3, "Map.ChangeLayer():")
781
782 newlayer = MapLayer(type=type, cmd=command, name=name,
783 active=l_active, hidden=l_hidden, opacity=l_opacity)
784
785 oldlayerindex = self.layers.index(layer)
786
787 # add maplayer to the list of layers
788 if layer:
789 self.layers[oldlayerindex] = newlayer
790
791 if l_render and not layer.Render():
792 raise gcmd.GException(_("Unable to render map layer <%s>.") %
793 (name))
794
795 return self.layers[-1]
796
797 def ChangeOpacity(self, layer, l_opacity):
798 """
799 Changes opacity value of map layer
800
801 @param layer layer instance
802 @param l_opacity opacity level <0;1>
803 """
804 # l_opacity must be <0;1>
805 if l_opacity < 0: l_opacity = 0
806 elif l_opacity > 1: l_opacity = 1
807
808 layer.opacity = l_opacity
809 Debug.msg (3, "Map.ChangeOpacity(): layer=%s, opacity=%f" % \
810 (layer.name, layer.opacity))
811
812 def ChangeLayerActive(self, layer, active):
813 """
814 Change the active state of a layer
815
816 @param layer layer instance
817 @param active to be rendered (True)
818 """
819 layer.active = active
820
821 Debug.msg (3, "Map.ChangeLayerActive(): name='%s' -> active=%d" % \
822 (layer.name, layer.active))
823
824 def ChangeLayerName (self, layer, name):
825 """
826 Change name of the layer
827
828 @param layer layer instance
829 @param name layer name to set up
830 """
831 Debug.msg (3, "Map.ChangeLayerName(): from=%s to=%s" % \
832 (layer.name, name))
833 layer.name = name
834
835 def RemoveLayer(self, name=None, id=None):
836 """
837 Removes layer from layer list of layers
838
839 Layer is defined by name@mapset or id.
840
841 @param name layer name (must be unique)
842 @param id layer index in layer list
843
844 @return removed layer on success
845 @return None on failure
846 """
847
848 # delete by name
849 if name:
850 retlayer = None
851 for layer in self.layers:
852 if layer.name == name:
853 retlayer = layer
854 os.remove(layer.mapfile)
855 os.remove(layer.maskfile)
856 self.layers.remove(layer)
857 return layer
858 # del by id
859 elif id != None:
860 return self.layers.pop(id)
861
862 return None
863
864 def GetLayerIndex(self, layer):
865 """
866 Returns index of layer in layer list.
867
868 @param layer layer instace
869
870 @return layer index
871 @return None
872 """
873
874 if layer in self.layers:
875 return self.layers.index(layer)
876 else:
877 return None
878
879 def AddOverlay(self, ovltype=None, type='overlay', command=None,
880 l_active=True, l_hidden=False, l_opacity=1, l_render=False):
881 """
882 Adds overlay (grid, barscale, others?) to list of overlays
883
884 @param ovltype overlay type
885 @param command GRASS command to render overlay
886 @param l_active overlay activated (True) or disabled (False)
887 @param l_render render an image (True)
888
889 @return new layer on success
890 @retutn None on failure
891 """
892
893 Debug.msg (2, "Map.AddOverlay(): cmd=%s, render=%d" % (command, l_render))
894 overlay = MapLayer(type='overlay', name=None, cmd=command,
895 active=l_active, hidden=l_hidden, opacity=l_opacity)
896
897 # add maplayer to the list of layers
898 self.overlays.append(overlay)
899
900 if l_render and command != '' and not overlay.Render():
901 raise gcmd.GException(_("Unable render overlay <%s>.") %
902 (name))
903
904 self.ovlookup[ovltype] = overlay
905
906 return self.overlays[-1]
907
908 def ChangeOverlay(self, ovltype, type, name, command,
909 l_active=True, l_hidden=False, l_opacity=1, l_render=False):
910 """
911 Change overlay properities
912
913 @param ovltype overlay type
914 @param type layer type
915 @param command GRASS command to render an overlay
916 @param l_active overlay is active (True) or disabled (False)
917 @param l_hidded not used here
918 @param l_opacity opacity level <0,1>
919 @param l_render render overlay (True)
920
921 @return new overlay instance
922 """
923
924 newoverlay = MapLayer(type='overlay', name=name, cmd=command,
925 active=l_active, hidden=l_hidden, opacity=l_opacity)
926
927 oldovlindex = self.overlays.index(self.ovlookup[ovltype])
928
929 # add overlay to the list of layers
930 if self.ovlookup[ovltype]:
931 self.overlays[oldovlindex] = newoverlay
932 self.ovlookup[ovltype] = newoverlay
933
934 if l_render and command != '' and not overlay.Render():
935 raise gcmd.GException(_("Unable render overlay <%s>.") %
936 (name))
937
938 return self.overlays[-1]
939
940 def changeOverlayActive(self, ovltype, activ):
941 """
942 Change active status of overlay
943 """
944 try:
945 overlay = self.ovlookup[ovltype]
946 overlay.active = activ
947 Debug.msg (3, "Map.changeOverlayActive(): type=%d, active=%d" % (type, activ))
948 except:
949 sys.stderr.write("Cannot change status of overlay index [%d]\n" % type)
950
951 def Clean(self):
952 """
953 Go trough all layers and remove them from layer list
954 Removes also l_mapfile and l_maskfile
955
956 @return 1 on faulure
957 @return None on success
958 """
959 try:
960 for layer in self.layers:
961 if layer.mapfile:
962 base = os.path.split(layer.mapfile)[0]
963 mapfile = os.path.split(layer.mapfile)[1]
964 tempbase = mapfile.split('.')[0]
965 basefile = os.path.join(base,tempbase)+r'.*'
966 for f in glob.glob(basefile):
967 os.remove(f)
968 self.layers.remove(layer)
969 for overlay in self.overlays:
970 if overlay.ovlfile:
971 base = os.path.split(overlay.ovlfile)[0]
972 mapfile = os.path.split(overlay.ovlfile)[1]
973 tempbase = mapfile.split('.')[0]
974 basefile = os.path.join(base,tempbase)+r'.*'
975 for f in glob.glob(basefile):
976 os.remove(f)
977 self.overlays.remove(overlay)
978 return None
979 except:
980 return 1
981 self.layers = []
982
983 def ReverseListOfLayers(self):
984 """Reverse list of layers"""
985 return self.layers.reverse()
986
987if __name__ == "__main__":
988 """
989 Test of Display class.
990 Usage: display=Render()
991 """
992
993 print "Initializing..."
994 os.system("g.region -d")
995
996 map = Map()
997 map.width = 640
998 map.height = 480
999
1000 map.AddLayer(item=None, type="raster", name="elevation.dem", command = "d.rast elevation.dem@PERMANENT catlist=1000-1500 -i", l_opacity=.7)
1001
1002 map.AddLayer(item=None, type="vector", name="streams", command = "d.vect streams@PERMANENT color=red width=3 type=line")
1003
1004 image = map.Render(force=True)
1005
1006 if image:
1007 os.system("display %s" % image)
Note: See TracBrowser for help on using the repository browser.