123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- """!
- @package mapdisp.main
- @brief Start Map Display as standalone application
- Classes:
- - mapdisp::DMonMap
- - mapdisp::Layer
- - mapdisp::LayerList
- - mapdisp::DMonGrassInterface
- - mapdisp::DMonFrame
- - mapdisp::MapApp
- Usage:
- python mapdisp/main.py monitor-identifier /path/to/map/file /path/to/command/file /path/to/env/file
- (C) 2006-2013 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- @author Michael Barton
- @author Jachym Cepicky
- @author Martin Landa <landa.martin gmail.com>
- @author Vaclav Petras <wenzeslaus gmail.com> (MapFrameBase)
- @author Anna Kratochvilova <kratochanna gmail.com> (MapFrameBase)
- """
- import os
- import sys
- if __name__ == "__main__":
- gui_wx_path = os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython')
- if gui_wx_path not in sys.path:
- sys.path.append(gui_wx_path)
- from core import globalvar
- import wx
- from core import utils
- from core.giface import StandaloneGrassInterface
- from core.gcmd import RunCommand
- from core.render import Map, MapLayer
- from core.utils import _
- from mapdisp.frame import MapFrame
- from grass.script import core as grass
- from core.debug import Debug
- from core.settings import UserSettings
- # for standalone app
- monFile = { 'cmd' : None,
- 'map' : None,
- 'env' : None,
- }
- monName = None
- monSize = list(globalvar.MAP_WINDOW_SIZE)
- class DMonMap(Map):
- def __init__(self, giface, cmdfile=None, mapfile=None):
- """!Map composition (stack of map layers and overlays)
- @param cmdline full path to the cmd file (defined by d.mon)
- @param mapfile full path to the map file (defined by d.mon)
- """
- Map.__init__(self)
- self._giface = giface
- # environment settings
- self.env = dict()
- self.cmdfile = cmdfile
- # list of layers for rendering added from cmd file
- # TODO temporary solution, layer managment by different tools in GRASS should be resovled
- self.ownedLayers = []
- if mapfile:
- self.mapfileCmd = mapfile
- self.maskfileCmd = os.path.splitext(mapfile)[0] + '.pgm'
- # generated file for g.pnmcomp output for rendering the map
- self.mapfile = monFile['map'] + '.ppm'
- def GetLayersFromCmdFile(self):
- """!Get list of map layers from cmdfile
- """
- if not self.cmdfile:
- return
- nlayers = 0
- try:
- fd = open(self.cmdfile, 'r')
- existingLayers = self.GetListOfLayers()
- # holds new rendreing order for every layer in existingLayers
- layersOrder = [-1] * len(self.GetListOfLayers())
- # next number in rendering order
- next_layer = 0;
- for line in fd.readlines():
- cmd = utils.split(line.strip())
- ltype = None
- try:
- ltype = utils.command2ltype[cmd[0]]
- except KeyError:
- grass.warning(_("Unsupported command %s.") % cmd[0])
- continue
- name = utils.GetLayerNameFromCmd(cmd, fullyQualified = True,
- layerType = ltype)[0]
- # creating temporary layer object to compare commands
- # neccessary to get the same format
- # supposing that there are no side effects
- tmpMapLayer = MapLayer(ltype = ltype, name = name,
- cmd = cmd, Map = None,
- active = False, hidden = True,
- opacity = 0)
- exists = False
- for i, layer in enumerate(existingLayers):
- if layer.GetCmd(string=True) == tmpMapLayer.GetCmd(string=True):
- exists = True
- if layersOrder[i] == -1:
- layersOrder[i] = next_layer;
- next_layer += 1
- # layer must be put higher in render order (same cmd was insered more times)
- # TODO delete rendurant cmds from cmd file?
- else:
- for j, l_order in enumerate(layersOrder):
- if l_order > layersOrder[i]:
- layersOrder[j] -= 1;
- layersOrder[i] = next_layer - 1;
- break
- if exists:
- continue
- newLayer = Map.AddLayer(self, ltype = ltype, command = cmd, active = True, name = name)
-
- existingLayers.append(newLayer)
- self.ownedLayers.append(newLayer)
- layersOrder.append(next_layer)
- next_layer += 1
- nlayers += 1
- reorderedLayers = [-1] * next_layer
- for i, layer in enumerate(existingLayers):
- # owned layer was not found in cmd file -> is deleted
- if layersOrder[i] == -1 and layer in self.ownedLayers:
- self.ownedLayers.remove(layer)
- self.DeleteLayer(layer)
- # other layer e. g. added by wx.vnet are added to the top
- elif layersOrder[i] == -1 and layer not in self.ownedLayers:
- reorderedLayers.append(layer)
-
- # owned layer found in cmd file is added into proper rendering position
- else:
- reorderedLayers[layersOrder[i]] = layer
- self.ReorderLayers(reorderedLayers)
- except IOError, e:
- grass.warning(_("Unable to read cmdfile '%(cmd)s'. Details: %(det)s") % \
- { 'cmd' : self.cmdfile, 'det' : e })
- return
- fd.close()
- self._giface.updateMap.emit()
- Debug.msg(1, "Map.GetLayersFromCmdFile(): cmdfile=%s" % self.cmdfile)
- Debug.msg(1, " nlayers=%d" % nlayers)
-
- def Render(self, *args, **kwargs):
- """!Render layer to image.
- For input params and returned data see overridden method in Map class.
- """
- currMon = grass.gisenv()['MONITOR']
- RunCommand('g.gisenv',
- unset = 'MONITOR') # GRASS_RENDER_IMMEDIATE doesn't like monitors
- ret = Map.Render(self, *args, **kwargs)
- RunCommand('g.gisenv',
- set = 'MONITOR=%s' % currMon)
-
- return ret
-
- def AddLayer(self, *args, **kwargs):
- """!Adds generic map layer to list of layers.
- For input params and returned data see overridden method in Map class.
- """
- currMon = grass.gisenv()['MONITOR']
- RunCommand('g.gisenv',
- unset = 'MONITOR') # GRASS_RENDER_IMMEDIATE doesn't like monitors
- driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
-
- if driver == 'png':
- os.environ["GRASS_RENDER_IMMEDIATE"] = "png"
- else:
- os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
- layer = Map.AddLayer(self, *args, **kwargs)
- del os.environ["GRASS_RENDER_IMMEDIATE"]
- RunCommand('g.gisenv',
- set = 'MONITOR=%s' % currMon)
-
- return layer
- class Layer(object):
- def __init__(self, maplayer):
- self._maplayer = maplayer
- def __getattr__(self, name):
- if name == 'cmd':
- return utils.CmdTupleToList(self._maplayer.GetCmd())
- elif hasattr(self._maplayer, name):
- return getattr(self._maplayer, name)
- elif name == 'maplayer':
- return self._maplayer
- elif name == 'type':
- return self._maplayer.GetType()
- #elif name == 'ctrl':
- elif name == 'label':
- return self._maplayer.GetName()
- #elif name == 'maplayer' : None,
- #elif name == 'propwin':
- class LayerList(object):
- def __init__(self, map):
- self._map = map
- # def __iter__(self):
- # for in :
- # yield
- def GetSelectedLayers(self, checkedOnly=True):
- # hidden and selected vs checked and selected
- items = self._map.GetListOfLayers()
- layers = []
- for item in items:
- layer = Layer(item)
- layers.append(layer)
- return layers
- class DMonGrassInterface(StandaloneGrassInterface):
- """!@implements GrassInterface"""
- def __init__(self, mapframe):
- StandaloneGrassInterface.__init__(self)
- self._mapframe = mapframe
- def GetLayerList(self):
- return LayerList(self._mapframe.GetMap())
- class DMonFrame(MapFrame):
- def OnZoomToMap(self, event):
- layers = self.MapWindow.GetMap().GetListOfLayers()
- self.MapWindow.ZoomToMap(layers = layers)
-
- class MapApp(wx.App):
- def OnInit(self):
- if not globalvar.CheckWxVersion([2, 9]):
- wx.InitAllImageHandlers()
- # actual use of StandaloneGrassInterface not yet tested
- # needed for adding functionality in future
- giface = DMonGrassInterface(None)
- if __name__ == "__main__":
- self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
- self.Map = DMonMap(giface=giface, cmdfile=monFile['cmd'],
- mapfile = monFile['map'])
- else:
- self.Map = None
- self.mapFrm = DMonFrame(parent = None, id = wx.ID_ANY, Map = self.Map,
- giface = giface, size = monSize)
- # FIXME: hack to solve dependency
- giface._mapframe = self.mapFrm
- # self.SetTopWindow(Map)
- self.mapFrm.GetMapWindow().SetAlwaysRenderEnabled(True)
- self.mapFrm.Show()
-
- if __name__ == "__main__":
- self.timer = wx.PyTimer(self.watcher)
- #check each 0.5s
- global mtime
- mtime = 500
- self.timer.Start(mtime)
-
- return True
-
- def OnExit(self):
- if __name__ == "__main__":
- # stop the timer
- # self.timer.Stop()
- # terminate thread
- for f in monFile.itervalues():
- grass.try_remove(f)
-
- def watcher(self):
- """!Redraw, if new layer appears (check's timestamp of
- cmdfile)
- """
- try:
- # GISBASE and other sytem enviromental variables can not be used
- # since the process inherited them from GRASS
- # raises exception when vaiable does not exists
- grass.gisenv()['GISDBASE']
- except KeyError:
- self.timer.Stop()
- return
-
- # todo: events
- try:
- currentCmdFileTime = os.path.getmtime(monFile['cmd'])
- if currentCmdFileTime > self.cmdTimeStamp:
- self.timer.Stop()
- self.cmdTimeStamp = currentCmdFileTime
- self.mapFrm.GetMap().GetLayersFromCmdFile()
- self.timer.Start(mtime)
- except OSError, e:
- grass.warning("%s" % e)
- self.timer.Stop()
- def GetMapFrame(self):
- """!Get Map Frame instance"""
- return self.mapFrm
- if __name__ == "__main__":
- # set command variable
- if len(sys.argv) < 5:
- print __doc__
- sys.exit(1)
-
- monName = sys.argv[1]
- monFile = { 'map' : sys.argv[2],
- 'cmd' : sys.argv[3],
- 'env' : sys.argv[4],
- }
- if len(sys.argv) >= 6:
- try:
- monSize[0] = int(sys.argv[5])
- except ValueError:
- pass
-
- if len(sys.argv) == 7:
- try:
- monSize[1] = int(sys.argv[6])
- except ValueError:
- pass
-
- grass.verbose(_("Starting map display <%s>...") % (monName))
- RunCommand('g.gisenv',
- set = 'MONITOR_%s_PID=%d' % (monName, os.getpid()))
-
- gmMap = MapApp(0)
- # set title
- gmMap.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
- monName +
- " - Location: " + grass.gisenv()["LOCATION_NAME"]))
-
- gmMap.MainLoop()
-
- grass.verbose(_("Stopping map display <%s>...") % (monName))
- # clean up GRASS env variables
- env = grass.gisenv()
- env_name = 'MONITOR_%s' % monName
- for key in env.keys():
- if key.find(env_name) == 0:
- RunCommand('g.gisenv',
- unset = '%s' % key)
- if key == 'MONITOR' and env[key] == monName:
- RunCommand('g.gisenv',
- unset = '%s' % key)
-
- sys.exit(0)
|