123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626 |
- """!
- @package gcp.mapdisplay
- @brief Display to manage ground control points with two toolbars, one
- for various display management functions, one for manipulating GCPs.
- Classes:
- - mapdisplay::MapFrame
- (C) 2006-2011 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 Markus Metz
- """
- import os
- import math
- import platform
- from core import globalvar
- import wx
- import wx.aui
- from core.render import EVT_UPDATE_PRGBAR
- from mapdisp.toolbars import MapToolbar
- from gcp.toolbars import GCPDisplayToolbar, GCPManToolbar
- from mapdisp.gprint import PrintOptions
- from core.gcmd import GMessage
- from gui_core.dialogs import GetImageHandlers, ImageSizeDialog
- from gui_core.mapdisp import SingleMapFrame
- from core.settings import UserSettings
- from mapdisp.mapwindow import BufferedWindow
- import mapdisp.statusbar as sb
- # for standalone app
- cmdfilename = None
- class MapFrame(SingleMapFrame):
- """!Main frame for map display window. Drawing takes place in
- child double buffered drawing window.
- """
- def __init__(self, parent=None, title=_("GRASS GIS Manage Ground Control Points"),
- toolbars=["gcpdisp"], tree=None, notebook=None, lmgr=None,
- page=None, Map=None, auimgr=None, name = 'GCPMapWindow', **kwargs):
- """!Main map display window with toolbars, statusbar and
- DrawWindow
- @param toolbars array of activated toolbars, e.g. ['map', 'digit']
- @param tree reference to layer tree
- @param notebook control book ID in Layer Manager
- @param lmgr Layer Manager
- @param page notebook page with layer tree
- @param Map instance of render.Map
- @param auimgs AUI manager
- @param kwargs wx.Frame attribures
- """
-
- SingleMapFrame.__init__(self, parent = parent, title = title,
- Map = Map, auimgr = auimgr, name = name, **kwargs)
-
- self._layerManager = lmgr # Layer Manager object
- self.tree = tree # Layer Manager layer tree object
- self.page = page # Notebook page holding the layer tree
- self.layerbook = notebook # Layer Manager layer tree notebook
- #
- # Add toolbars
- #
- for toolb in toolbars:
- self.AddToolbar(toolb)
- self.activemap = self.toolbars['gcpdisp'].togglemap
- self.activemap.SetSelection(0)
-
- self.SrcMap = self.grwiz.SrcMap # instance of render.Map
- self.TgtMap = self.grwiz.TgtMap # instance of render.Map
- self._mgr.SetDockSizeConstraint(0.5, 0.5)
- #
- # Add statusbar
- #
-
- # items for choice
- self.statusbarItems = [sb.SbCoordinates,
- sb.SbRegionExtent,
- sb.SbCompRegionExtent,
- sb.SbShowRegion,
- sb.SbResolution,
- sb.SbDisplayGeometry,
- sb.SbMapScale,
- sb.SbProjection,
- sb.SbGoToGCP,
- sb.SbRMSError]
-
-
- # create statusbar and its manager
- statusbar = self.CreateStatusBar(number = 4, style = 0)
- statusbar.SetStatusWidths([-5, -2, -1, -1])
- self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
-
- # fill statusbar manager
- self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
- self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
- self.statusbarManager.AddStatusbarItem(sb.SbRender(self, statusbar = statusbar, position = 3))
-
- self.statusbarManager.SetMode(8) # goto GCP
- self.statusbarManager.Update()
-
- #
- # Init map display (buffered DC & set default cursor)
- #
- self.grwiz.SwitchEnv('source')
- self.SrcMapWindow = BufferedWindow(self, id=wx.ID_ANY,
- Map=self.SrcMap, tree=self.tree, lmgr=self._layerManager)
- self.grwiz.SwitchEnv('target')
- self.TgtMapWindow = BufferedWindow(self, id=wx.ID_ANY,
- Map=self.TgtMap, tree=self.tree, lmgr=self._layerManager)
- self.MapWindow = self.SrcMapWindow
- self.Map = self.SrcMap
- self.SrcMapWindow.SetCursor(self.cursors["cross"])
- self.TgtMapWindow.SetCursor(self.cursors["cross"])
- #
- # initialize region values
- #
- self._initMap(Map = self.SrcMap)
- self._initMap(Map = self.TgtMap)
- #
- # Bind various events
- #
- self.Bind(EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
- self.activemap.Bind(wx.EVT_CHOICE, self.OnUpdateActive)
-
- #
- # Update fancy gui style
- #
- # AuiManager wants a CentrePane, workaround to get two equally sized windows
- self.list = self.CreateGCPList()
- #self.SrcMapWindow.SetSize((300, 300))
- #self.TgtMapWindow.SetSize((300, 300))
- self.list.SetSize((100, 150))
- self._mgr.AddPane(self.list, wx.aui.AuiPaneInfo().
- Name("gcplist").Caption(_("GCP List")).LeftDockable(False).
- RightDockable(False).PinButton().FloatingSize((600,200)).
- CloseButton(False).DestroyOnClose(True).
- Top().Layer(1).MinSize((200,100)))
- self._mgr.AddPane(self.SrcMapWindow, wx.aui.AuiPaneInfo().
- Name("source").Caption(_("Source Display")).Dockable(False).
- CloseButton(False).DestroyOnClose(True).Floatable(False).
- Centre())
- self._mgr.AddPane(self.TgtMapWindow, wx.aui.AuiPaneInfo().
- Name("target").Caption(_("Target Display")).Dockable(False).
- CloseButton(False).DestroyOnClose(True).Floatable(False).
- Right().Layer(0))
- srcwidth, srcheight = self.SrcMapWindow.GetSize()
- tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
- srcwidth = (srcwidth + tgtwidth) / 2
- self._mgr.GetPane("target").Hide()
- self._mgr.Update()
- self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
- self._mgr.GetPane("target").BestSize((srcwidth, srcheight))
- if self.show_target:
- self._mgr.GetPane("target").Show()
- else:
- self.activemap.Enable(False)
- # needed by Mac OS, does not harm on Linux, breaks display on Windows
- if platform.system() != 'Windows':
- self._mgr.Update()
- #
- # Init print module and classes
- #
- self.printopt = PrintOptions(self, self.MapWindow)
-
- #
- # Initialization of digitization tool
- #
- self.digit = None
- # set active map
- self.MapWindow = self.SrcMapWindow
- self.Map = self.SrcMap
-
- # do not init zoom history here, that happens when zooming to map(s)
- #
- # Re-use dialogs
- #
- self.dialogs = {}
- self.dialogs['attributes'] = None
- self.dialogs['category'] = None
- self.dialogs['barscale'] = None
- self.dialogs['legend'] = None
- self.decorationDialog = None # decoration/overlays
- def AddToolbar(self, name):
- """!Add defined toolbar to the window
-
- Currently known toolbars are:
- - 'map' - basic map toolbar
- - 'vdigit' - vector digitizer
- - 'gcpdisp' - GCP Manager, Display
- - 'gcpman' - GCP Manager, points management
- - 'nviz' - 3D view mode
- """
- # default toolbar
- if name == "map":
- self.toolbars['map'] = MapToolbar(self, self.Map)
- self._mgr.AddPane(self.toolbars['map'],
- wx.aui.AuiPaneInfo().
- Name("maptoolbar").Caption(_("Map Toolbar")).
- ToolbarPane().Top().
- LeftDockable(False).RightDockable(False).
- BottomDockable(False).TopDockable(True).
- CloseButton(False).Layer(2).
- BestSize((self.toolbars['map'].GetSize())))
- # GCP display
- elif name == "gcpdisp":
- self.toolbars['gcpdisp'] = GCPDisplayToolbar(self)
- self._mgr.AddPane(self.toolbars['gcpdisp'],
- wx.aui.AuiPaneInfo().
- Name("gcpdisplaytoolbar").Caption(_("GCP Display toolbar")).
- ToolbarPane().Top().
- LeftDockable(False).RightDockable(False).
- BottomDockable(False).TopDockable(True).
- CloseButton(False).Layer(2))
- if self.show_target == False:
- self.toolbars['gcpdisp'].Enable('zoommenu', enable = False)
- self.toolbars['gcpman'] = GCPManToolbar(self)
- self._mgr.AddPane(self.toolbars['gcpman'],
- wx.aui.AuiPaneInfo().
- Name("gcpmanagertoolbar").Caption(_("GCP Manager toolbar")).
- ToolbarPane().Top().Row(1).
- LeftDockable(False).RightDockable(False).
- BottomDockable(False).TopDockable(True).
- CloseButton(False).Layer(2))
-
- self._mgr.Update()
- def OnUpdateProgress(self, event):
- """
- Update progress bar info
- """
- self.GetProgressBar().SetValue(event.value)
-
- event.Skip()
-
- def OnFocus(self, event):
- """
- Change choicebook page to match display.
- Or set display for georectifying
- """
- if self._layerManager and \
- self._layerManager.gcpmanagement:
- # in GCP Management, set focus to current MapWindow for mouse actions
- self.OnPointer(event)
- self.MapWindow.SetFocus()
- else:
- # change bookcontrol page to page associated with display
- # GCP Manager: use bookcontrol?
- if self.page:
- pgnum = self.layerbook.GetPageIndex(self.page)
- if pgnum > -1:
- self.layerbook.SetSelection(pgnum)
-
- event.Skip()
- def OnDraw(self, event):
- """!Re-display current map composition
- """
- self.MapWindow.UpdateMap(render = False)
-
- def OnRender(self, event):
- """!Re-render map composition (each map layer)
- """
- # delete tmp map layers (queries)
- qlayer = self.Map.GetListOfLayers(l_name=globalvar.QUERYLAYER)
- for layer in qlayer:
- self.Map.DeleteLayer(layer)
- self.SrcMapWindow.UpdateMap(render=True)
- if self.show_target:
- self.TgtMapWindow.UpdateMap(render=True)
-
- # update statusbar
- self.StatusbarUpdate()
- def OnPointer(self, event):
- """!Pointer button clicked
- """
- # change the cursor
- self.SrcMapWindow.SetCursor(self.cursors["cross"])
- self.SrcMapWindow.mouse['use'] = "pointer"
- self.SrcMapWindow.mouse['box'] = "point"
- self.TgtMapWindow.SetCursor(self.cursors["cross"])
- self.TgtMapWindow.mouse['use'] = "pointer"
- self.TgtMapWindow.mouse['box'] = "point"
- def OnZoomIn(self, event):
- """
- Zoom in the map.
- Set mouse cursor, zoombox attributes, and zoom direction
- """
- self.toolbars['gcpdisp'].OnTool(event)
- self.toolbars['gcpdisp'].action['desc'] = ''
-
- self.MapWindow.mouse['use'] = "zoom"
- self.MapWindow.mouse['box'] = "box"
- self.MapWindow.zoomtype = 1
- self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
-
- # change the cursor
- self.MapWindow.SetCursor(self.cursors["cross"])
- if self.MapWindow == self.SrcMapWindow:
- win = self.TgtMapWindow
- elif self.MapWindow == self.TgtMapWindow:
- win = self.SrcMapWindow
- win.mouse['use'] = "zoom"
- win.mouse['box'] = "box"
- win.zoomtype = 1
- win.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
-
- # change the cursor
- win.SetCursor(self.cursors["cross"])
- def OnZoomOut(self, event):
- """
- Zoom out the map.
- Set mouse cursor, zoombox attributes, and zoom direction
- """
- self.toolbars['gcpdisp'].OnTool(event)
- self.toolbars['gcpdisp'].action['desc'] = ''
-
- self.MapWindow.mouse['use'] = "zoom"
- self.MapWindow.mouse['box'] = "box"
- self.MapWindow.zoomtype = -1
- self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
-
- # change the cursor
- self.MapWindow.SetCursor(self.cursors["cross"])
- if self.MapWindow == self.SrcMapWindow:
- win = self.TgtMapWindow
- elif self.MapWindow == self.TgtMapWindow:
- win = self.SrcMapWindow
- win.mouse['use'] = "zoom"
- win.mouse['box'] = "box"
- win.zoomtype = -1
- win.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
-
- # change the cursor
- win.SetCursor(self.cursors["cross"])
- def OnPan(self, event):
- """
- Panning, set mouse to drag
- """
- self.toolbars['gcpdisp'].OnTool(event)
- self.toolbars['gcpdisp'].action['desc'] = ''
-
- self.MapWindow.mouse['use'] = "pan"
- self.MapWindow.mouse['box'] = "pan"
- self.MapWindow.zoomtype = 0
-
- # change the cursor
- self.MapWindow.SetCursor(self.cursors["hand"])
- if self.MapWindow == self.SrcMapWindow:
- win = self.TgtMapWindow
- elif self.MapWindow == self.TgtMapWindow:
- win = self.SrcMapWindow
- win.mouse['use'] = "pan"
- win.mouse['box'] = "pan"
- win.zoomtype = 0
-
- # change the cursor
- win.SetCursor(self.cursors["hand"])
- def OnErase(self, event):
- """
- Erase the canvas
- """
- self.MapWindow.EraseMap()
- if self.MapWindow == self.SrcMapWindow:
- win = self.TgtMapWindow
- elif self.MapWindow == self.TgtMapWindow:
- win = self.SrcMapWindow
- win.EraseMap()
- def OnZoomRegion(self, event):
- """
- Zoom to region
- """
- self.Map.getRegion()
- self.Map.getResolution()
- self.UpdateMap()
- # event.Skip()
- def OnAlignRegion(self, event):
- """
- Align region
- """
- if not self.Map.alignRegion:
- self.Map.alignRegion = True
- else:
- self.Map.alignRegion = False
- # event.Skip()
-
- def SaveToFile(self, event):
- """!Save map to image
- """
- img = self.MapWindow.img
- if not img:
- GMessage(parent = self,
- message = _("Nothing to render (empty map). Operation canceled."))
- return
- filetype, ltype = GetImageHandlers(img)
- # get size
- dlg = ImageSizeDialog(self)
- dlg.CentreOnParent()
- if dlg.ShowModal() != wx.ID_OK:
- dlg.Destroy()
- return
- width, height = dlg.GetValues()
- dlg.Destroy()
-
- # get filename
- dlg = wx.FileDialog(parent = self,
- message = _("Choose a file name to save the image "
- "(no need to add extension)"),
- wildcard = filetype,
- style=wx.SAVE | wx.FD_OVERWRITE_PROMPT)
-
- if dlg.ShowModal() == wx.ID_OK:
- path = dlg.GetPath()
- if not path:
- dlg.Destroy()
- return
-
- base, ext = os.path.splitext(path)
- fileType = ltype[dlg.GetFilterIndex()]['type']
- extType = ltype[dlg.GetFilterIndex()]['ext']
- if ext != extType:
- path = base + '.' + extType
-
- self.MapWindow.SaveToFile(path, fileType,
- width, height)
-
- dlg.Destroy()
- def PrintMenu(self, event):
- """
- Print options and output menu for map display
- """
- point = wx.GetMousePosition()
- printmenu = wx.Menu()
- # Add items to the menu
- setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
- printmenu.AppendItem(setup)
- self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
- preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
- printmenu.AppendItem(preview)
- self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
- doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
- printmenu.AppendItem(doprint)
- self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)
- # Popup the menu. If an item is selected then its handler
- # will be called before PopupMenu returns.
- self.PopupMenu(printmenu)
- printmenu.Destroy()
-
-
- def FormatDist(self, dist):
- """!Format length numbers and units in a nice way,
- as a function of length. From code by Hamish Bowman
- Grass Development Team 2006"""
- mapunits = self.Map.projinfo['units']
- if mapunits == 'metres': mapunits = 'meters'
- outunits = mapunits
- dist = float(dist)
- divisor = 1.0
- # figure out which units to use
- if mapunits == 'meters':
- if dist > 2500.0:
- outunits = 'km'
- divisor = 1000.0
- else: outunits = 'm'
- elif mapunits == 'feet':
- # nano-bug: we match any "feet", but US Survey feet is really
- # 5279.9894 per statute mile, or 10.6' per 1000 miles. As >1000
- # miles the tick markers are rounded to the nearest 10th of a
- # mile (528'), the difference in foot flavours is ignored.
- if dist > 5280.0:
- outunits = 'miles'
- divisor = 5280.0
- else:
- outunits = 'ft'
- elif 'degree' in mapunits:
- if dist < 1:
- outunits = 'min'
- divisor = (1/60.0)
- else:
- outunits = 'deg'
- # format numbers in a nice way
- if (dist/divisor) >= 2500.0:
- outdist = round(dist/divisor)
- elif (dist/divisor) >= 1000.0:
- outdist = round(dist/divisor,1)
- elif (dist/divisor) > 0.0:
- outdist = round(dist/divisor,int(math.ceil(3-math.log10(dist/divisor))))
- else:
- outdist = float(dist/divisor)
- return (outdist, outunits)
- def OnZoomToRaster(self, event):
- """!
- Set display extents to match selected raster map (ignore NULLs)
- """
- self.MapWindow.ZoomToMap(ignoreNulls = True)
-
- def OnZoomToSaved(self, event):
- """!Set display geometry to match extents in
- saved region file
- """
- self.MapWindow.ZoomToSaved()
-
- def OnDisplayToWind(self, event):
- """!Set computational region (WIND file) to match display
- extents
- """
- self.MapWindow.DisplayToWind()
-
- def SaveDisplayRegion(self, event):
- """!Save display extents to named region file.
- """
- self.MapWindow.SaveDisplayRegion()
-
- def OnZoomMenu(self, event):
- """!Popup Zoom menu
- """
- point = wx.GetMousePosition()
- zoommenu = wx.Menu()
- # Add items to the menu
- zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to computational region (set with g.region)'))
- zoommenu.AppendItem(zoomwind)
- self.Bind(wx.EVT_MENU, self.OnZoomToWind, zoomwind)
- zoomdefault = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to default region'))
- zoommenu.AppendItem(zoomdefault)
- self.Bind(wx.EVT_MENU, self.OnZoomToDefault, zoomdefault)
- zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
- zoommenu.AppendItem(zoomsaved)
- self.Bind(wx.EVT_MENU, self.OnZoomToSaved, zoomsaved)
- savewind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Set computational region from display'))
- zoommenu.AppendItem(savewind)
- self.Bind(wx.EVT_MENU, self.OnDisplayToWind, savewind)
- savezoom = wx.MenuItem(zoommenu, wx.ID_ANY, _('Save display geometry to named region'))
- zoommenu.AppendItem(savezoom)
- self.Bind(wx.EVT_MENU, self.SaveDisplayRegion, savezoom)
- # Popup the menu. If an item is selected then its handler
- # will be called before PopupMenu returns.
- self.PopupMenu(zoommenu)
- zoommenu.Destroy()
-
-
- def IsStandalone(self):
- """!Check if Map display is standalone"""
- if self._layerManager:
- return False
-
- return True
-
- def GetLayerManager(self):
- """!Get reference to Layer Manager
- @return window reference
- @return None (if standalone)
- """
- return self._layerManager
-
- def GetSrcWindow(self):
- return self.SrcMapWindow
-
- def GetTgtWindow(self):
- return self.TgtMapWindow
-
- def GetShowTarget(self):
- return self.show_target
-
- def GetMapToolbar(self):
- """!Returns toolbar with zooming tools"""
- return self.toolbars['gcpdisp']
|