|
GRASS Programmer's Manual
6.5.svn(2012)-r51648
|
00001 """! 00002 @package gui_core.mapdisp 00003 00004 @brief Base classes for Map display window 00005 00006 Classes: 00007 - mapdisp::MapFrameBase 00008 00009 (C) 2009-2011 by the GRASS Development Team 00010 00011 This program is free software under the GNU General Public License 00012 (>=v2). Read the file COPYING that comes with GRASS for details. 00013 00014 @author Martin Landa <landa.martin gmail.com> 00015 @author Michael Barton <michael.barton@asu.edu> 00016 """ 00017 00018 import os 00019 import sys 00020 00021 import wx 00022 00023 from core import globalvar 00024 from core.debug import Debug 00025 00026 from grass.script import core as grass 00027 00028 class MapFrameBase(wx.Frame): 00029 """!Base class for map display window 00030 00031 Derived class must use statusbarManager or override 00032 GetProperty, SetProperty and HasProperty methods. 00033 If derived class enables and disables auto-rendering, 00034 it should override IsAutoRendered method. 00035 """ 00036 def __init__(self, parent = None, id = wx.ID_ANY, title = None, 00037 style = wx.DEFAULT_FRAME_STYLE, toolbars = None, 00038 Map = None, auimgr = None, name = None, **kwargs): 00039 """! 00040 @param toolbars array of activated toolbars, e.g. ['map', 'digit'] 00041 @param Map instance of render.Map 00042 @param auimgs AUI manager 00043 @param name frame name 00044 @param kwargs wx.Frame attributes 00045 """ 00046 00047 00048 self.Map = Map # instance of render.Map 00049 self.parent = parent 00050 00051 wx.Frame.__init__(self, parent, id, title, style = style, name = name, **kwargs) 00052 00053 # available cursors 00054 self.cursors = { 00055 # default: cross 00056 # "default" : wx.StockCursor(wx.CURSOR_DEFAULT), 00057 "default" : wx.StockCursor(wx.CURSOR_ARROW), 00058 "cross" : wx.StockCursor(wx.CURSOR_CROSS), 00059 "hand" : wx.StockCursor(wx.CURSOR_HAND), 00060 "pencil" : wx.StockCursor(wx.CURSOR_PENCIL), 00061 "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE) 00062 } 00063 00064 # 00065 # set the size & system icon 00066 # 00067 self.SetClientSize(self.GetSize()) 00068 self.iconsize = (16, 16) 00069 00070 self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO)) 00071 00072 # toolbars 00073 self.toolbars = {} 00074 00075 # 00076 # Fancy gui 00077 # 00078 self._mgr = wx.aui.AuiManager(self) 00079 00080 def _initMap(self, map): 00081 """!Initialize map display, set dimensions and map region 00082 """ 00083 if not grass.find_program('g.region', ['--help']): 00084 sys.exit(_("GRASS module '%s' not found. Unable to start map " 00085 "display window.") % 'g.region') 00086 00087 self.width, self.height = self.GetClientSize() 00088 00089 Debug.msg(2, "MapFrame._initMap():") 00090 map.ChangeMapSize(self.GetClientSize()) 00091 map.region = map.GetRegion() # g.region -upgc 00092 # self.Map.SetRegion() # adjust region to match display window 00093 00094 def SetProperty(self, name, value): 00095 """!Sets property""" 00096 self.statusbarManager.SetProperty(name, value) 00097 00098 def GetProperty(self, name): 00099 """!Returns property""" 00100 return self.statusbarManager.GetProperty(name) 00101 00102 def HasProperty(self, name): 00103 """!Checks whether object has property""" 00104 return self.statusbarManager.HasProperty(name) 00105 00106 def GetPPM(self): 00107 """! Get pixel per meter 00108 00109 @todo now computed every time, is it necessary? 00110 @todo enable user to specify ppm (and store it in UserSettings) 00111 """ 00112 # TODO: need to be fixed... 00113 ### screen X region problem 00114 ### user should specify ppm 00115 dc = wx.ScreenDC() 00116 dpSizePx = wx.DisplaySize() # display size in pixels 00117 dpSizeMM = wx.DisplaySizeMM() # display size in mm (system) 00118 dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4) # inches 00119 sysPpi = dc.GetPPI() 00120 comPpi = (dpSizePx[0] / dpSizeIn[0], 00121 dpSizePx[1] / dpSizeIn[1]) 00122 00123 ppi = comPpi # pixel per inch 00124 ppm = ((ppi[0] / 2.54) * 100, # pixel per meter 00125 (ppi[1] / 2.54) * 100) 00126 00127 Debug.msg(4, "MapFrameBase.GetPPM(): size: px=%d,%d mm=%f,%f " 00128 "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % \ 00129 (dpSizePx[0], dpSizePx[1], dpSizeMM[0], dpSizeMM[1], 00130 dpSizeIn[0], dpSizeIn[1], 00131 sysPpi[0], sysPpi[1], comPpi[0], comPpi[1], 00132 ppm[0], ppm[1])) 00133 00134 return ppm 00135 00136 def SetMapScale(self, value, map = None): 00137 """! Set current map scale 00138 00139 @param value scale value (n if scale is 1:n) 00140 @param map Map instance (if none self.Map is used) 00141 """ 00142 if not map: 00143 map = self.Map 00144 00145 region = self.Map.region 00146 dEW = value * (region['cols'] / self.GetPPM()[0]) 00147 dNS = value * (region['rows'] / self.GetPPM()[1]) 00148 region['n'] = region['center_northing'] + dNS / 2. 00149 region['s'] = region['center_northing'] - dNS / 2. 00150 region['w'] = region['center_easting'] - dEW / 2. 00151 region['e'] = region['center_easting'] + dEW / 2. 00152 00153 # add to zoom history 00154 self.GetWindow().ZoomHistory(region['n'], region['s'], 00155 region['e'], region['w']) 00156 00157 def GetMapScale(self, map = None): 00158 """! Get current map scale 00159 00160 @param map Map instance (if none self.Map is used) 00161 """ 00162 if not map: 00163 map = self.Map 00164 00165 region = map.region 00166 ppm = self.GetPPM() 00167 00168 heightCm = region['rows'] / ppm[1] * 100 00169 widthCm = region['cols'] / ppm[0] * 100 00170 00171 Debug.msg(4, "MapFrame.GetMapScale(): width_cm=%f, height_cm=%f" % 00172 (widthCm, heightCm)) 00173 00174 xscale = (region['e'] - region['w']) / (region['cols'] / ppm[0]) 00175 yscale = (region['n'] - region['s']) / (region['rows'] / ppm[1]) 00176 scale = (xscale + yscale) / 2. 00177 00178 Debug.msg(3, "MapFrame.GetMapScale(): xscale=%f, yscale=%f -> scale=%f" % \ 00179 (xscale, yscale, scale)) 00180 00181 return scale 00182 00183 def GetProgressBar(self): 00184 """!Returns progress bar 00185 00186 Progress bar can be used by other classes. 00187 """ 00188 return self.statusbarManager.GetProgressBar() 00189 00190 def GetMap(self): 00191 """!Returns current Map instance 00192 """ 00193 return self.Map 00194 00195 def GetWindow(self): 00196 """!Get map window""" 00197 return self.MapWindow 00198 00199 def GetMapToolbar(self): 00200 """!Returns toolbar with zooming tools""" 00201 raise NotImplementedError() 00202 00203 def GetToolbar(self, name): 00204 """!Returns toolbar if exists else None. 00205 00206 Toolbars dictionary contains currently used toolbars only. 00207 """ 00208 if name in self.toolbars: 00209 return self.toolbars[name] 00210 00211 return None 00212 00213 def StatusbarUpdate(self): 00214 """!Update statusbar content""" 00215 self.statusbarManager.Update() 00216 00217 def IsAutoRendered(self): 00218 """!Check if auto-rendering is enabled""" 00219 return self.GetProperty('render') 00220 00221 def CoordinatesChanged(self): 00222 """!Shows current coordinates on statusbar. 00223 00224 Used in BufferedWindow to report change of map coordinates (under mouse cursor). 00225 """ 00226 self.statusbarManager.ShowItem('coordinates') 00227 00228 def StatusbarReposition(self): 00229 """!Reposition items in statusbar""" 00230 self.statusbarManager.Reposition() 00231 00232 def StatusbarEnableLongHelp(self, enable = True): 00233 """!Enable/disable toolbars long help""" 00234 for toolbar in self.toolbars.itervalues(): 00235 toolbar.EnableLongHelp(enable) 00236 00237 def IsStandalone(self): 00238 """!Check if Map display is standalone""" 00239 raise NotImplementedError("IsStandalone") 00240 00241 def OnRender(self, event): 00242 """!Re-render map composition (each map layer) 00243 """ 00244 raise NotImplementedError("OnRender") 00245 00246 def OnDraw(self, event): 00247 """!Re-display current map composition 00248 """ 00249 self.MapWindow.UpdateMap(render = False) 00250 00251 def OnErase(self, event): 00252 """!Erase the canvas 00253 """ 00254 self.MapWindow.EraseMap() 00255 00256 def OnZoomIn(self, event): 00257 """!Zoom in the map. 00258 Set mouse cursor, zoombox attributes, and zoom direction 00259 """ 00260 toolbar = self.GetMapToolbar() 00261 self._switchTool(toolbar, event) 00262 00263 win = self.GetWindow() 00264 self._prepareZoom(mapWindow = win, zoomType = 1) 00265 00266 def OnZoomOut(self, event): 00267 """!Zoom out the map. 00268 Set mouse cursor, zoombox attributes, and zoom direction 00269 """ 00270 toolbar = self.GetMapToolbar() 00271 self._switchTool(toolbar, event) 00272 00273 win = self.GetWindow() 00274 self._prepareZoom(mapWindow = win, zoomType = -1) 00275 00276 def _prepareZoom(self, mapWindow, zoomType): 00277 """!Prepares MapWindow for zoom, toggles toolbar 00278 00279 @param mapWindow MapWindow to prepare 00280 @param zoomType 1 for zoom in, -1 for zoom out 00281 """ 00282 mapWindow.mouse['use'] = "zoom" 00283 mapWindow.mouse['box'] = "box" 00284 mapWindow.zoomtype = zoomType 00285 mapWindow.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH) 00286 00287 # change the cursor 00288 mapWindow.SetCursor(self.cursors["cross"]) 00289 00290 def _switchTool(self, toolbar, event): 00291 """!Helper function to switch tools""" 00292 if toolbar: 00293 toolbar.OnTool(event) 00294 toolbar.action['desc'] = '' 00295 00296 def OnPan(self, event): 00297 """!Panning, set mouse to drag 00298 """ 00299 toolbar = self.GetMapToolbar() 00300 self._switchTool(toolbar, event) 00301 00302 win = self.GetWindow() 00303 self._preparePan(mapWindow = win) 00304 00305 def _preparePan(self, mapWindow): 00306 """!Prepares MapWindow for pan, toggles toolbar 00307 00308 @param mapWindow MapWindow to prepare 00309 """ 00310 mapWindow.mouse['use'] = "pan" 00311 mapWindow.mouse['box'] = "pan" 00312 mapWindow.zoomtype = 0 00313 00314 # change the cursor 00315 mapWindow.SetCursor(self.cursors["hand"]) 00316 00317 def OnZoomBack(self, event): 00318 """!Zoom last (previously stored position) 00319 """ 00320 self.MapWindow.ZoomBack() 00321 00322 def OnZoomToMap(self, event): 00323 """! 00324 Set display extents to match selected raster (including NULLs) 00325 or vector map. 00326 """ 00327 self.MapWindow.ZoomToMap(layers = self.Map.GetListOfLayers()) 00328 00329 def OnZoomToWind(self, event): 00330 """!Set display geometry to match computational region 00331 settings (set with g.region) 00332 """ 00333 self.MapWindow.ZoomToWind() 00334 00335 def OnZoomToDefault(self, event): 00336 """!Set display geometry to match default region settings 00337 """ 00338 self.MapWindow.ZoomToDefault()