main.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. """!
  2. @package mapdisp.main
  3. @brief Start Map Display as standalone application
  4. Classes:
  5. - mapdisp::MapApp
  6. Usage:
  7. python mapdisp/main.py monitor-identifier /path/to/map/file /path/to/command/file /path/to/env/file
  8. (C) 2006-2011 by the GRASS Development Team
  9. This program is free software under the GNU General Public License
  10. (>=v2). Read the file COPYING that comes with GRASS for details.
  11. @author Michael Barton
  12. @author Jachym Cepicky
  13. @author Martin Landa <landa.martin gmail.com>
  14. @author Vaclav Petras <wenzeslaus gmail.com> (MapFrameBase)
  15. @author Anna Kratochvilova <kratochanna gmail.com> (MapFrameBase)
  16. """
  17. import os
  18. import sys
  19. if __name__ == "__main__":
  20. sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
  21. from core import globalvar
  22. import wx
  23. from core import utils
  24. from core.gcmd import RunCommand
  25. from core.render import Map
  26. from mapdisp.frame import MapFrame
  27. from grass.script import core as grass
  28. from core.debug import Debug
  29. # for standalone app
  30. monFile = { 'cmd' : None,
  31. 'map' : None,
  32. 'env' : None,
  33. }
  34. monName = None
  35. monSize = list(globalvar.MAP_WINDOW_SIZE)
  36. class DMonMap(Map):
  37. def __init__(self, gisrc = None, cmdfile = None, mapfile = None, envfile = None, monitor = None):
  38. """!Map composition (stack of map layers and overlays)
  39. @param cmdline full path to the cmd file (defined by d.mon)
  40. @param mapfile full path to the map file (defined by d.mon)
  41. @param envfile full path to the env file (defined by d.mon)
  42. @param monitor name of monitor (defined by d.mon)
  43. """
  44. Map.__init__(self)
  45. # environment settings
  46. self.env = dict()
  47. self.cmdfile = cmdfile
  48. self.envfile = envfile
  49. self.monitor = monitor
  50. if mapfile:
  51. self.mapfileCmd = mapfile
  52. self.maskfileCmd = os.path.splitext(mapfile)[0] + '.pgm'
  53. # generated file for g.pnmcomp output for rendering the map
  54. self.mapfile = grass.tempfile(create = False) + '.ppm'
  55. # GRASS environment variable (for rendering)
  56. env = {"GRASS_BACKGROUNDCOLOR" : "FFFFFF",
  57. "GRASS_COMPRESSION" : "0",
  58. "GRASS_TRUECOLOR" : "TRUE",
  59. "GRASS_TRANSPARENT" : "TRUE",
  60. "GRASS_PNG_READ" : "FALSE",
  61. }
  62. self._writeEnvFile(env)
  63. self._writeEnvFile({"GRASS_PNG_READ" : "TRUE"})
  64. for k, v in env.iteritems():
  65. os.environ[k] = v
  66. def GetLayersFromCmdFile(self):
  67. """!Get list of map layers from cmdfile
  68. """
  69. if not self.cmdfile:
  70. return
  71. nlayers = 0
  72. try:
  73. fd = open(self.cmdfile, 'r')
  74. for line in fd.readlines():
  75. cmd = utils.split(line.strip())
  76. ltype = None
  77. if cmd[0] == 'd.rast':
  78. ltype = 'raster'
  79. elif cmd[0] == 'd.vect':
  80. ltype = 'vector'
  81. name = utils.GetLayerNameFromCmd(cmd, fullyQualified = True,
  82. layerType = ltype)[0]
  83. self.AddLayer(type = ltype, command = cmd, l_active = False, name = name)
  84. nlayers += 1
  85. except IOError, e:
  86. grass.warning(_("Unable to read cmdfile '%(cmd)s'. Details: %(det)s") % \
  87. { 'cmd' : self.cmdfile, 'det' : e })
  88. return
  89. fd.close()
  90. Debug.msg(1, "Map.GetLayersFromCmdFile(): cmdfile=%s" % self.cmdfile)
  91. Debug.msg(1, " nlayers=%d" % nlayers)
  92. def _parseCmdFile(self):
  93. """!Parse cmd file for standalone application
  94. """
  95. nlayers = 0
  96. try:
  97. fd = open(self.cmdfile, 'r')
  98. grass.try_remove(self.mapfile)
  99. cmdLines = fd.readlines()
  100. RunCommand('g.gisenv',
  101. set = 'MONITOR_%s_CMDFILE=' % self.monitor)
  102. for cmd in cmdLines:
  103. cmdStr = utils.split(cmd.strip())
  104. cmd = utils.CmdToTuple(cmdStr)
  105. RunCommand(cmd[0], **cmd[1])
  106. nlayers += 1
  107. RunCommand('g.gisenv',
  108. set = 'MONITOR_%s_CMDFILE=%s' % (self.monitor, self.cmdfile))
  109. except IOError, e:
  110. grass.warning(_("Unable to read cmdfile '%(cmd)s'. Details: %(det)s") % \
  111. { 'cmd' : self.cmdfile, 'det' : e })
  112. return
  113. fd.close()
  114. Debug.msg(1, "Map.__parseCmdFile(): cmdfile=%s" % self.cmdfile)
  115. Debug.msg(1, " nlayers=%d" % nlayers)
  116. return nlayers
  117. def _renderCmdFile(self, force, windres):
  118. if not force:
  119. return ([self.mapfileCmd],
  120. [self.maskfileCmd],
  121. ['1.0'])
  122. region = os.environ["GRASS_REGION"] = self.SetRegion(windres)
  123. self._writeEnvFile({'GRASS_REGION' : region})
  124. currMon = grass.gisenv()['MONITOR']
  125. if currMon != self.monitor:
  126. RunCommand('g.gisenv',
  127. set = 'MONITOR=%s' % self.monitor)
  128. grass.try_remove(self.mapfileCmd) # GRASS_PNG_READ is TRUE
  129. nlayers = self._parseCmdFile()
  130. if self.overlays:
  131. RunCommand('g.gisenv',
  132. unset = 'MONITOR') # GRASS_RENDER_IMMEDIATE doesn't like monitors
  133. driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
  134. if driver == 'png':
  135. os.environ["GRASS_RENDER_IMMEDIATE"] = "png"
  136. else:
  137. os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
  138. self._renderLayers(overlaysOnly = True)
  139. del os.environ["GRASS_RENDER_IMMEDIATE"]
  140. RunCommand('g.gisenv',
  141. set = 'MONITOR=%s' % currMon)
  142. if currMon != self.monitor:
  143. RunCommand('g.gisenv',
  144. set = 'MONITOR=%s' % currMon)
  145. if nlayers > 0:
  146. return ([self.mapfileCmd],
  147. [self.maskfileCmd],
  148. ['1.0'])
  149. else:
  150. return ([], [], [])
  151. def _writeEnvFile(self, data):
  152. """!Write display-related variable to the file (used for
  153. standalone app)
  154. """
  155. if not self.envfile:
  156. return
  157. try:
  158. fd = open(self.envfile, "r")
  159. for line in fd.readlines():
  160. key, value = line.split('=')
  161. if key not in data.keys():
  162. data[key] = value
  163. fd.close()
  164. fd = open(self.envfile, "w")
  165. for k, v in data.iteritems():
  166. fd.write('%s=%s\n' % (k.strip(), str(v).strip()))
  167. except IOError, e:
  168. grass.warning(_("Unable to open file '%(file)s' for writting. Details: %(det)s") % \
  169. { 'cmd' : self.envfile, 'det' : e })
  170. return
  171. fd.close()
  172. def ChangeMapSize(self, (width, height)):
  173. """!Change size of rendered map.
  174. @param width,height map size
  175. """
  176. Map.ChangeMapSize(self, (width, height))
  177. self._writeEnvFile({'GRASS_WIDTH' : self.width,
  178. 'GRASS_HEIGHT' : self.height})
  179. def GetMapsMasksAndOpacities(self, force, guiFrame, windres):
  180. """!
  181. Used by Render function.
  182. @return maps, masks, opacities
  183. """
  184. return self._renderCmdFile(force, windres)
  185. class MapApp(wx.App):
  186. def OnInit(self):
  187. wx.InitAllImageHandlers()
  188. if __name__ == "__main__":
  189. self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
  190. self.Map = DMonMap(cmdfile = monFile['cmd'], mapfile = monFile['map'],
  191. envfile = monFile['env'], monitor = monName)
  192. else:
  193. self.Map = None
  194. self.mapFrm = MapFrame(parent = None, id = wx.ID_ANY, Map = self.Map,
  195. size = monSize)
  196. # self.SetTopWindow(Map)
  197. self.mapFrm.GetMapWindow().SetAlwaysRenderEnabled(True)
  198. self.mapFrm.Show()
  199. if __name__ == "__main__":
  200. self.timer = wx.PyTimer(self.watcher)
  201. #check each 0.5s
  202. global mtime
  203. mtime = 500
  204. self.timer.Start(mtime)
  205. return True
  206. def OnExit(self):
  207. if __name__ == "__main__":
  208. # stop the timer
  209. # self.timer.Stop()
  210. # terminate thread
  211. for f in monFile.itervalues():
  212. grass.try_remove(f)
  213. def watcher(self):
  214. """!Redraw, if new layer appears (check's timestamp of
  215. cmdfile)
  216. """
  217. # todo: events
  218. if os.path.getmtime(monFile['cmd']) > self.cmdTimeStamp:
  219. self.timer.Stop()
  220. self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
  221. self.mapFrm.OnDraw(None)
  222. self.mapFrm.GetMap().GetLayersFromCmdFile()
  223. self.timer.Start(mtime)
  224. if __name__ == "__main__":
  225. # set command variable
  226. if len(sys.argv) < 5:
  227. print __doc__
  228. sys.exit(1)
  229. monName = sys.argv[1]
  230. monFile = { 'map' : sys.argv[2],
  231. 'cmd' : sys.argv[3],
  232. 'env' : sys.argv[4],
  233. }
  234. if len(sys.argv) >= 6:
  235. try:
  236. monSize[0] = int(sys.argv[5])
  237. except ValueError:
  238. pass
  239. if len(sys.argv) == 7:
  240. try:
  241. monSize[1] = int(sys.argv[6])
  242. except ValueError:
  243. pass
  244. import gettext
  245. gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
  246. grass.verbose(_("Starting map display <%s>...") % (monName))
  247. RunCommand('g.gisenv',
  248. set = 'MONITOR_%s_PID=%d' % (monName, os.getpid()))
  249. gmMap = MapApp(0)
  250. # set title
  251. gmMap.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
  252. monName +
  253. " - Location: " + grass.gisenv()["LOCATION_NAME"]))
  254. gmMap.MainLoop()
  255. grass.verbose(_("Stopping map display <%s>...") % (monName))
  256. # clean up GRASS env variables
  257. env = grass.gisenv()
  258. env_name = 'MONITOR_%s' % monName
  259. for key in env.keys():
  260. if key.find(env_name) == 0:
  261. RunCommand('g.gisenv',
  262. unset = '%s' % key)
  263. if key == 'MONITOR' and env[key] == monName:
  264. RunCommand('g.gisenv',
  265. unset = '%s' % key)
  266. sys.exit(0)