123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- """
- @package photo2image.ip2i_mapdisplay
- @brief Display to manage ground control points with two toolbars, one
- for various display management functions, one for manipulating GCPs.
- Classes:
- - mapdisplay::MapPanel
- (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 platform
- from core import globalvar
- import wx
- import wx.aui
- 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 SingleMapPanel
- from gui_core.wrap import Menu
- from mapwin.buffered import BufferedMapWindow
- import mapdisp.statusbar as sb
- import gcp.statusbar as sbgcp
- # for standalone app
- cmdfilename = None
- class MapPanel(SingleMapPanel):
- """Main panel for map display window. Drawing takes place in
- child double buffered drawing window.
- """
- def __init__(
- self,
- parent,
- giface,
- title=_("GRASS GIS Manage Location of Tick Points on a Scanned Photo"),
- toolbars=["gcpdisp"],
- Map=None,
- auimgr=None,
- name="GCPMapWindow",
- **kwargs,
- ):
- """Main map display window with toolbars, statusbar and
- DrawWindow
- :param giface: GRASS interface instance
- :param title: window title
- :param toolbars: array of activated toolbars, e.g. ['map', 'digit']
- :param map: instance of render.Map
- :param auimgs: AUI manager
- :param kwargs: wx.Frame attribures
- """
- SingleMapPanel.__init__(
- self,
- parent=parent,
- giface=giface,
- title=title,
- Map=Map,
- auimgr=auimgr,
- name=name,
- **kwargs,
- )
- self._giface = giface
- self.mapWindowProperties.alignExtent = True
- #
- # 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
- statusbarItems = [
- sb.SbCoordinates,
- sb.SbRegionExtent,
- sb.SbCompRegionExtent,
- sb.SbDisplayGeometry,
- sb.SbMapScale,
- sbgcp.SbGoToGCP,
- sbgcp.SbRMSError,
- ]
- # create statusbar and its manager
- self.statusbar = self.CreateStatusbar(statusbarItems)
- #
- # Init map display (buffered DC & set default cursor)
- #
- self.grwiz.SwitchEnv("source")
- self.SrcMapWindow = BufferedMapWindow(
- parent=self,
- giface=self._giface,
- id=wx.ID_ANY,
- properties=self.mapWindowProperties,
- Map=self.SrcMap,
- )
- self.grwiz.SwitchEnv("target")
- self.TgtMapWindow = BufferedMapWindow(
- parent=self,
- giface=self._giface,
- id=wx.ID_ANY,
- properties=self.mapWindowProperties,
- Map=self.TgtMap,
- )
- self.MapWindow = self.SrcMapWindow
- self.Map = self.SrcMap
- self._setUpMapWindow(self.SrcMapWindow)
- self._setUpMapWindow(self.TgtMapWindow)
- self.SrcMapWindow.SetNamedCursor("cross")
- self.TgtMapWindow.SetNamedCursor("cross")
- # used to switch current map (combo box in toolbar)
- self.SrcMapWindow.mouseEntered.connect(
- lambda: self._setActiveMapWindow(self.SrcMapWindow)
- )
- self.TgtMapWindow.mouseEntered.connect(
- lambda: self._setActiveMapWindow(self.TgtMapWindow)
- )
- #
- # initialize region values
- #
- self._initMap(Map=self.SrcMap)
- self._initMap(Map=self.TgtMap)
- self.GetMapToolbar().SelectDefault()
- #
- # Bind various events
- #
- self.activemap.Bind(wx.EVT_CHOICE, self.OnUpdateActive)
- self.Bind(wx.EVT_SIZE, self.OnSize)
- #
- # Update fancy gui style
- #
- # AuiManager wants a CentrePane, workaround to get two equally sized
- # windows
- self.list = self.CreateGCPList()
- # set Go To GCP item as active in statusbar
- self.mapWindowProperties.sbItem = 5
- # self.SrcMapWindow.SetSize((300, 300))
- # self.TgtMapWindow.SetSize((300, 300))
- self.list.SetSize((100, 150))
- self._addPanes()
- 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 _setUpMapWindow(self, mapWindow):
- # TODO: almost the same implementation as for MapPanelBase (only names differ)
- # enable or disable zoom history tool
- mapWindow.zoomHistoryAvailable.connect(
- lambda: self.GetMapToolbar().Enable("zoomback", enable=True)
- )
- mapWindow.zoomHistoryUnavailable.connect(
- lambda: self.GetMapToolbar().Enable("zoomback", enable=False)
- )
- mapWindow.mouseMoving.connect(self.CoordinatesChanged)
- def AddToolbar(self, name):
- """Add defined toolbar to the window
- Currently known toolbars are:
- - 'map' - basic map toolbar
- - 'gcpdisp' - GCP Manager, Display
- - 'gcpman' - GCP Manager, points management
- - 'nviz' - 3D view mode
- """
- # default toolbar
- if name == "map":
- if "map" not in self.toolbars:
- self.toolbars["map"] = MapToolbar(
- self, self._toolSwitcher, self._giface
- )
- 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":
- if "gcpdisp" not in self.toolbars:
- self.toolbars["gcpdisp"] = GCPDisplayToolbar(self, self._toolSwitcher)
- 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 is False:
- self.toolbars["gcpdisp"].Enable("zoommenu", enable=False)
- if "gcpman" not in self.toolbars:
- 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 _addPanes(self):
- """Add mapwindows, toolbars and statusbar to aui manager"""
- 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),
- )
- # statusbar
- self.AddStatusbarPane()
- def OnUpdateProgress(self, event):
- """
- Update progress bar info
- """
- self.GetProgressBar().UpdateProgress(event.layer, event.map)
- event.Skip()
- def OnFocus(self, event):
- """
- Change choicebook page to match display.
- Or set display for georectifying
- """
- # was in if layer manager but considering the state it was executed
- # always, moreover, there is no layer manager dependent code
- # in GCP Management, set focus to current MapWindow for mouse actions
- self.OnPointer(event)
- self.MapWindow.SetFocus()
- 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)"""
- # FIXME: remove qlayer code or use RemoveQueryLayer() now in mapdisp.frame
- # delete tmp map layers (queries)
- qlayer = self.Map.GetListOfLayers(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"""
- self.SrcMapWindow.SetModePointer()
- self.TgtMapWindow.SetModePointer()
- # change the default cursor
- self.SrcMapWindow.SetNamedCursor("cross")
- self.TgtMapWindow.SetNamedCursor("cross")
- def OnZoomIn(self, event):
- """Zoom in the map."""
- self.SrcMapWindow.SetModeZoomIn()
- self.TgtMapWindow.SetModeZoomIn()
- def OnZoomOut(self, event):
- """Zoom out the map."""
- self.SrcMapWindow.SetModeZoomOut()
- self.TgtMapWindow.SetModeZoomOut()
- def OnPan(self, event):
- """Panning, set mouse to drag"""
- self.SrcMapWindow.SetModePan()
- self.TgtMapWindow.SetModePan()
- 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 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.FD_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 = 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 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.SetRegion(zoomOnly=True)
- 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 = 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 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"]
- def _setActiveMapWindow(self, mapWindow):
- if not self.MapWindow == mapWindow:
- self.MapWindow = mapWindow
- self.Map = mapWindow.Map
- self.UpdateActive(mapWindow)
- # needed for wingrass
- self.SetFocus()
|