2 @package mapdisp.mapwindow
4 @brief Map display canvas - buffered window.
7 - mapwindow::BufferedWindow
9 (C) 2006-2011 by the GRASS Development Team
11 This program is free software under the GNU General Public License
12 (>=v2). Read the file COPYING that comes with GRASS for details.
14 @author Martin Landa <landa.martin gmail.com>
15 @author Michael Barton
16 @author Jachym Cepicky
29 from core.gcmd import RunCommand, GException, GError, GMessage
40 """!A Buffered window class (2D view mode)
42 Superclass for VDigitWindow (vector digitizer).
44 When the drawing needs to change, you app needs to call the
45 UpdateMap() method. Since the drawing is stored in a bitmap, you
46 can also save the drawing to file by calling the
49 def __init__(self, parent, id = wx.ID_ANY,
50 Map =
None, tree =
None, lmgr =
None, overlays =
None,
51 style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
52 MapWindow.__init__(self, parent, id, Map, tree, lmgr, **kwargs)
53 wx.Window.__init__(self, parent, id, style = style, **kwargs)
70 self.Bind(wx.EVT_PAINT, self.
OnPaint)
71 self.Bind(wx.EVT_SIZE, self.
OnSize)
72 self.Bind(wx.EVT_IDLE, self.
OnIdle)
107 self.Bind(wx.EVT_ERASE_BACKGROUND,
lambda x:
None)
113 def _definePseudoDC(self):
114 """!Define PseudoDC objects to use
125 def _bindMouseEvents(self):
127 self.Bind(wx.EVT_MOTION, self.
OnMotion)
129 def Draw(self, pdc, img = None, drawid = None, pdctype = 'image', coords = [0, 0, 0, 0]):
130 """!Draws map and overlay decorations
133 if pdctype ==
'image' and img:
135 elif pdctype ==
'clear':
140 if img
and pdctype ==
'image':
147 bg = wx.TRANSPARENT_BRUSH
149 bg = wx.Brush(self.GetBackgroundColour())
151 pdc.SetBackground(bg)
153 Debug.msg (5,
"BufferedWindow.Draw(): id=%s, pdctype = %s, coord=%s" % \
154 (drawid, pdctype, coords))
157 if drawid
is not None:
160 if pdctype ==
'clear':
163 pdc.SetBackground(bg)
171 if pdctype ==
'image':
172 bitmap = wx.BitmapFromImage(img)
173 w,h = bitmap.GetSize()
174 pdc.DrawBitmap(bitmap, coords[0], coords[1],
True)
175 pdc.SetIdBounds(drawid, wx.Rect(coords[0],coords[1], w, h))
177 elif pdctype ==
'box':
179 pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
181 x2 =
max(coords[0],coords[2])
182 x1 =
min(coords[0],coords[2])
183 y2 =
max(coords[1],coords[3])
184 y1 =
min(coords[1],coords[3])
187 rect = wx.Rect(x1, y1, rwidth, rheight)
188 pdc.DrawRectangleRect(rect)
189 pdc.SetIdBounds(drawid, rect)
191 elif pdctype ==
'line':
193 pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
195 pdc.DrawLinePoint(wx.Point(coords[0], coords[1]),wx.Point(coords[2], coords[3]))
196 pdc.SetIdBounds(drawid, wx.Rect(coords[0], coords[1], coords[2], coords[3]))
198 elif pdctype ==
'polyline':
200 pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
202 if (len(coords) < 2):
205 while i < len(coords):
206 pdc.DrawLinePoint(wx.Point(coords[i-1][0], coords[i-1][1]),
207 wx.Point(coords[i][0], coords[i][1]))
222 pdc.SetIdBounds(drawid, wx.Rect(x1,y1,x2,y2))
225 elif pdctype ==
'point':
228 pdc.DrawPoint(coords[0], coords[1])
229 coordsBound = (coords[0] - 5,
233 pdc.SetIdBounds(drawid, wx.Rect(coordsBound))
235 elif pdctype ==
'text':
236 if not img[
'active']:
238 if 'rotation' in img:
239 rotation = float(img[
'rotation'])
242 w, h = self.GetFullTextExtent(img[
'text'])[0:2]
243 pdc.SetFont(img[
'font'])
244 pdc.SetTextForeground(img[
'color'])
247 pdc.DrawText(img[
'text'], coords[0], coords[1])
249 pdc.DrawRotatedText(img[
'text'], coords[0], coords[1], rotation)
250 pdc.SetIdBounds(drawid, bbox)
259 """!Return text boundary data
261 @param textinfo text metadata (text, font, color, rotation)
262 @param coords reference point
264 @return coords of nonrotated text bbox (TL corner)
265 @return bbox of rotated text bbox (wx.Rect)
266 @return relCoords are text coord inside bbox
268 if 'rotation' in textinfo:
269 rotation = float(textinfo[
'rotation'])
273 coords = textinfo[
'coords']
274 bbox = wx.Rect(coords[0], coords[1], 0, 0)
276 Debug.msg (4,
"BufferedWindow.TextBounds(): text=%s, rotation=%f" % \
277 (textinfo[
'text'], rotation))
281 self.SetFont(textinfo[
'font'])
283 w, h = self.GetTextExtent(textinfo[
'text'])
286 bbox[2], bbox[3] = w, h
288 return coords, bbox, relCoords
292 boxh = math.fabs(math.sin(math.radians(rotation)) * w) + h
293 boxw = math.fabs(math.cos(math.radians(rotation)) * w) + h
294 if rotation > 0
and rotation < 90:
296 relCoords = (0, boxh)
297 elif rotation >= 90
and rotation < 180:
300 relCoords = (boxw, boxh)
301 elif rotation >= 180
and rotation < 270:
303 relCoords = (boxw, 0)
308 return coords, bbox, relCoords
313 """!Draw PseudoDC's to buffered paint DC
315 If self.redrawAll is False on self.pdcTmp content is re-drawn
317 Debug.msg(4,
"BufferedWindow.OnPaint(): redrawAll=%s" % self.
redrawAll)
319 dc = wx.BufferedPaintDC(self, self.
buffer)
327 rgn = self.GetUpdateRegion().GetBox()
328 dc.SetClippingRect(rgn)
337 self.pdc.DrawToDCClipped(dc, rgn)
340 if hasattr(self,
"digit"):
344 self.pdcVector.DrawToDCClipped(gcdc, rgn)
345 except NotImplementedError, e:
346 print >> sys.stderr, e
347 self.pdcVector.DrawToDCClipped(dc, rgn)
353 self.pdc.DrawToDC(dc)
355 if hasattr(self,
"digit"):
359 self.pdcVector.DrawToDC(gcdc)
360 except NotImplementedError, e:
361 print >> sys.stderr, e
362 self.pdcVector.DrawToDC(dc)
366 self.
bufferLast = dc.GetAsBitmap(wx.Rect(0, 0, self.Map.width, self.Map.height))
368 self.pdc.DrawBitmap(self.
bufferLast, 0, 0,
False)
369 self.pdc.DrawToDC(dc)
374 self.pdcDec.DrawToDC(gcdc)
375 except NotImplementedError, e:
376 print >> sys.stderr, e
377 self.pdcDec.DrawToDC(dc)
381 self.pdcTmp.DrawToDC(dc)
387 """!Scale map image so that it is the same size as the Window
389 Debug.msg(3,
"BufferedWindow.OnSize():")
392 self.Map.ChangeMapSize(self.GetClientSize())
400 self.
buffer = wx.EmptyBitmap(
max(1, self.Map.width),
max(1, self.Map.height))
406 if self.
img and self.Map.width + self.Map.height > 0:
407 self.
img = self.img.Scale(self.Map.width, self.Map.height)
408 if len(self.Map.GetListOfLayers()) > 0:
415 self.parent.StatusbarReposition()
418 self.parent.StatusbarUpdate()
421 """!Only re-render a composite map image from GRASS during
422 idle time instead of multiple times during resizing.
430 """!This draws the pseudo DC to a buffer that can be saved to
433 @param FileName file name
434 @param FileType type of bitmap
435 @param width image width
436 @param height image height
438 busy = wx.BusyInfo(message = _(
"Please wait, exporting image..."),
442 self.Map.ChangeMapSize((width, height))
443 ibuffer = wx.EmptyBitmap(
max(1, width),
max(1, height))
444 self.Map.Render(force =
True, windres =
True)
447 self.
Draw(self.
pdc, img, drawid = 99)
450 cSize = self.GetClientSizeTuple()
451 ratio = float(width) / cSize[0], float(height) / cSize[1]
456 if self.
imagedict[img][
'layer'].IsActive():
458 coords = int(ratio[0] * self.
overlays[id].coords[0]),\
459 int(ratio[1] * self.
overlays[id].coords[1])
460 self.
Draw(self.
pdc, img = img, drawid = id,
461 pdctype = self.
overlays[id].pdcType, coords = coords)
464 for id
in self.textdict.keys():
466 oldCoords = textinfo[
'coords']
467 textinfo[
'coords'] = ratio[0] * textinfo[
'coords'][0],\
468 ratio[1] * textinfo[
'coords'][1]
472 textinfo[
'coords'] = oldCoords
474 dc = wx.BufferedDC(
None, ibuffer)
477 self.pdc.DrawToDC(dc)
479 self.pdcVector.DrawToDC(dc)
480 ibuffer.SaveFile(FileName, FileType)
488 """!Converts rendered overlay files to wx.Image
490 Updates self.imagedict
492 @return list of images
495 for overlay
in self.Map.GetListOfLayers(l_type =
"overlay", l_active =
True):
496 if overlay.mapfile
is not None \
497 and os.path.isfile(overlay.mapfile)
and os.path.getsize(overlay.mapfile):
498 img = wx.Image(overlay.mapfile, wx.BITMAP_TYPE_ANY)
500 for key
in self.imagedict.keys():
501 if self.
imagedict[key][
'id'] == overlay.id:
504 self.
imagedict[img] = {
'id' : overlay.id,
511 """!Converts redered map files to wx.Image
513 Updates self.imagedict (id=99)
515 @return wx.Image instance (map composition)
518 if self.
mapfile and self.Map.mapfile
and os.path.isfile(self.Map.mapfile)
and \
519 os.path.getsize(self.Map.mapfile):
520 img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
524 for key
in self.imagedict.keys():
532 def UpdateMap(self, render = True, renderVector = True):
533 """!Updates the canvas anytime there is a change to the
534 underlaying images or to the geometry of the canvas.
536 @param render re-render map composition
537 @param renderVector re-render vector map layer enabled for editing (used for digitizer)
549 if render
or renderVector:
550 self.parent.GetProgressBar().Show()
551 if self.parent.GetProgressBar().GetRange() > 0:
552 self.parent.GetProgressBar().
SetValue(1)
558 if self.
tree and self.tree.reorder:
559 self.tree.ReorderLayers()
563 self.tree.rerender =
False
568 self.Map.ChangeMapSize(self.GetClientSize())
569 if self.parent.GetProperty(
'resolution'):
574 self.
mapfile = self.Map.Render(force =
True, mapWindow = self.
parent,
577 self.
mapfile = self.Map.Render(force =
False, mapWindow = self.
parent)
578 except GException, e:
579 GError(message = e.value)
587 for pdc
in (self.
pdc,
597 self.
Draw(self.
pdc, pdctype =
'clear')
609 if renderVector
and hasattr(self,
"digit"):
616 if self.
imagedict[img][
'layer'].IsActive():
618 self.
Draw(self.
pdc, img = img, drawid = id,
621 for id
in self.textdict.keys():
623 pdctype =
'text', coords = [10, 10, 10, 10])
634 if not self.parent.IsStandalone()
and \
635 self.parent.GetLayerManager().gcpmanagement:
637 if self.parent.GetMapToolbar():
638 if self == self.parent.TgtMapWindow:
643 self.parent.DrawGCP(coordtype)
648 if self.
mouse[
"use"] ==
"measure":
651 self.
mouse[
'use'] =
'pointer'
652 self.
mouse[
'box'] =
'point'
653 self.
mouse[
'end'] = [0, 0]
654 self.SetCursor(self.parent.cursors[
"default"])
661 self.parent.GetProgressBar().Hide()
667 self.parent.StatusbarUpdate()
669 Debug.msg (1,
"BufferedWindow.UpdateMap(): render=%s, renderVector=%s -> time=%g" % \
670 (render, renderVector, (stop-start)))
675 """!Draw computational region extent in the display
677 Display region is drawn as a blue box inside the computational region,
678 computational region inside a display region as a red box).
680 if hasattr(self,
"regionCoords"):
681 compReg = self.Map.GetRegion()
682 dispReg = self.Map.GetCurrentRegion()
685 self.
polypen = wx.Pen(colour = wx.Colour(0, 0, 255, 128), width = 3, style = wx.SOLID)
688 self.
polypen = wx.Pen(colour = wx.Colour(255, 0, 0, 128),
689 width = 3, style = wx.SOLID)
693 self.regionCoords.append((reg[
'w'], reg[
'n']))
694 self.regionCoords.append((reg[
'e'], reg[
'n']))
695 self.regionCoords.append((reg[
'e'], reg[
's']))
696 self.regionCoords.append((reg[
'w'], reg[
's']))
697 self.regionCoords.append((reg[
'w'], reg[
'n']))
703 Test if 'region' is inside of 'refRegion'
705 @param region input region
706 @param refRegion reference region (e.g. computational region)
708 @return True if region is inside of refRegion
711 if region[
's'] >= refRegion[
's']
and \
712 region[
'n'] <= refRegion[
'n']
and \
713 region[
'w'] >= refRegion[
'w']
and \
714 region[
'e'] <= refRegion[
'e']:
722 self.
Draw(self.
pdc, pdctype =
'clear')
724 if hasattr(self,
"digit"):
731 """!Drag the entire map image for panning.
735 dc = wx.BufferedDC(wx.ClientDC(self))
736 dc.SetBackground(wx.Brush(
"White"))
740 self.dragimg.BeginDrag((0, 0), self)
741 self.dragimg.GetImageRect(moveto)
742 self.dragimg.Move(moveto)
744 self.dragimg.DoDrawImage(dc, moveto)
745 self.dragimg.EndDrag()
748 """!Drag an overlay decoration item
750 if id == 99
or id ==
'' or id ==
None:
return
751 Debug.msg (5,
"BufferedWindow.DragItem(): id=%d" % id)
753 dx = event.GetX() - x
754 dy = event.GetY() - y
755 self.pdc.SetBackground(wx.Brush(self.GetBackgroundColour()))
756 r = self.pdc.GetIdBounds(id)
758 r = wx.Rect(r[0], r[1], r[2], r[3])
760 rtop = (r[0],r[1]-r[3],r[2],r[3])
762 rleft = (r[0]-r[2],r[1],r[2],r[3])
764 self.pdc.TranslateId(id, dx, dy)
766 r2 = self.pdc.GetIdBounds(id)
768 r2 = wx.Rect(r[0], r[1], r[2], r[3])
771 self.
textdict[id][
'coords'][0] += dx
772 self.
textdict[id][
'coords'][1] += dy
775 self.RefreshRect(r,
False)
776 self.
lastpos = (event.GetX(), event.GetY())
778 def MouseDraw(self, pdc = None, begin = None, end = None):
779 """!Mouse box or line from 'begin' to 'end'
781 If not given from self.mouse['begin'] to self.mouse['end'].
787 begin = self.
mouse[
'begin']
789 end = self.
mouse[
'end']
791 Debug.msg (5,
"BufferedWindow.MouseDraw(): use=%s, box=%s, begin=%f,%f, end=%f,%f" % \
793 begin[0], begin[1], end[0], end[1]))
795 if self.
mouse[
'box'] ==
"box":
797 mousecoords = [begin[0], begin[1],
799 r = pdc.GetIdBounds(boxid)
801 r = wx.Rect(r[0], r[1], r[2], r[3])
807 self.RefreshRect(r,
False)
809 self.
Draw(pdc, drawid = boxid, pdctype =
'box', coords = mousecoords)
811 elif self.
mouse[
'box'] ==
"line":
813 mousecoords = [begin[0], begin[1], \
815 x1 =
min(begin[0],end[0])
816 x2 =
max(begin[0],end[0])
817 y1 =
min(begin[1],end[1])
818 y2 =
max(begin[1],end[1])
819 r = wx.Rect(x1,y1,x2-x1,y2-y1)
825 self.RefreshRect(r,
False)
827 self.
Draw(pdc, drawid = self.
lineid, pdctype =
'line', coords = mousecoords)
830 """!Draw polyline in PseudoDC
832 Set self.pline to wx.NEW_ID + 1
834 polycoords - list of polyline vertices, geographical coordinates
835 (if not given, self.polycoords is used)
843 if len(polycoords) > 0:
850 self.
Draw(pdc, drawid = self.
plineid, pdctype =
'polyline', coords = coords)
852 Debug.msg (4,
"BufferedWindow.DrawLines(): coords=%s, id=%s" % \
859 def DrawCross(self, pdc, coords, size, rotation = 0,
860 text =
None, textAlign =
'lr', textOffset = (5, 5)):
861 """!Draw cross in PseudoDC
863 @todo implement rotation
866 @param coord center coordinates
867 @param rotation rotate symbol
868 @param text draw also text (text, font, color, rotation)
869 @param textAlign alignment (default 'lower-right')
870 @textOffset offset for text (from center point)
872 Debug.msg(4,
"BufferedWindow.DrawCross(): pdc=%s, coords=%s, size=%d" % \
874 coordsCross = ((coords[0] - size, coords[1], coords[0] + size, coords[1]),
875 (coords[0], coords[1] - size, coords[0], coords[1] + size))
878 for lineCoords
in coordsCross:
879 self.
Draw(pdc, drawid = self.
lineid, pdctype =
'line', coords = lineCoords)
884 if textAlign ==
'ul':
885 coord = [coords[0] - textOffset[0], coords[1] - textOffset[1], 0, 0]
886 elif textAlign ==
'ur':
887 coord = [coords[0] + textOffset[0], coords[1] - textOffset[1], 0, 0]
888 elif textAlign ==
'lr':
889 coord = [coords[0] + textOffset[0], coords[1] + textOffset[1], 0, 0]
891 coord = [coords[0] - textOffset[0], coords[1] + textOffset[1], 0, 0]
893 self.
Draw(pdc, img = text,
894 pdctype =
'text', coords = coord)
898 def _computeZoomToPointAndRecenter(self, position, zoomtype):
899 """!Computes zoom parameters for recenter mode.
901 Computes begin and end parameters for Zoom() method.
902 Used for zooming by single click (not box)
903 and mouse wheel zooming (zoom and recenter mode).
906 begin = (position[0] - self.Map.width / 4,
907 position[1] - self.Map.height / 4)
908 end = (position[0] + self.Map.width / 4,
909 position[1] + self.Map.height / 4)
911 begin = ((self.Map.width - position[0]) / 2,
912 (self.Map.height - position[1]) / 2)
913 end = (begin[0] + self.Map.width / 2,
914 begin[1] + self.Map.height / 2)
918 """!Mouse motion and button click notifier
924 if event.GetWheelRotation() != 0:
928 elif event.LeftDown():
936 elif event.Dragging():
940 elif event.ButtonDClick():
944 elif event.MiddleDown():
948 elif event.MiddleUp():
952 elif event.RightDown():
956 elif event.RightUp():
959 elif event.Entering():
966 """!Mouse wheel moved
968 zoomBehaviour = UserSettings.Get(group =
'display',
969 key =
'mouseWheelZoom',
970 subkey =
'selection')
971 if zoomBehaviour == 2:
976 current = event.GetPositionTuple()[:]
977 wheel = event.GetWheelRotation()
978 Debug.msg (5,
"BufferedWindow.MouseAction(): wheel=%d" % wheel)
984 if UserSettings.Get(group =
'display',
985 key =
'scrollDirection',
986 subkey =
'selection'):
989 if zoomBehaviour == 0:
992 elif zoomBehaviour == 1:
993 begin = (current[0]/2, current[1]/2)
994 end = ((self.Map.width - current[0])/2 + current[0],
995 (self.Map.height - current[1])/2 + current[1])
998 self.
Zoom(begin, end, zoomtype)
1004 self.parent.StatusbarUpdate()
1012 Debug.msg (5,
"BufferedWindow.MouseAction(): Dragging")
1013 current = event.GetPositionTuple()[:]
1014 previous = self.
mouse[
'begin']
1015 move = (current[0] - previous[0],
1016 current[1] - previous[1])
1018 if hasattr(self,
"digit"):
1019 digitToolbar = self.toolbar
1024 if self.
mouse[
'use'] ==
'pan' or \
1025 event.MiddleIsDown():
1029 elif (self.
mouse[
'use'] ==
'pointer' and
1030 not digitToolbar
and
1036 if (self.
mouse[
'use'] ==
'pointer' and
1040 self.
mouse[
'end'] = event.GetPositionTuple()[:]
1041 if (event.LeftIsDown()
and
1042 not (digitToolbar
and
1043 digitToolbar.GetAction()
in (
"moveLine",)
and
1044 self.digit.GetDisplay().GetSelected() > 0)):
1048 """!Left mouse button pressed
1050 Debug.msg (5,
"BufferedWindow.OnLeftDown(): use=%s" % \
1053 self.
mouse[
'begin'] = event.GetPositionTuple()[:]
1055 if self.
mouse[
"use"]
in [
"measure",
"profile"]:
1064 elif self.
mouse[
'use']
in (
'zoom',
'legend'):
1068 elif self.
mouse[
"use"] ==
"pointer" and \
1069 hasattr(self,
"digit"):
1070 if event.ControlDown():
1071 self.OnLeftDownUndo(event)
1073 self._onLeftDown(event)
1075 elif self.
mouse[
'use'] ==
'pointer':
1092 """!Left mouse button released
1094 Debug.msg (5,
"BufferedWindow.OnLeftUp(): use=%s" % \
1097 self.
mouse[
'end'] = event.GetPositionTuple()[:]
1099 if self.
mouse[
'use']
in [
"zoom",
"pan"]:
1101 begin = self.
mouse[
'begin']
1102 end = self.
mouse[
'end']
1104 if self.
mouse[
'use'] ==
'zoom':
1106 if begin[0] - end[0] == 0
or \
1107 begin[1] - end[1] == 0:
1115 self.parent.StatusbarUpdate()
1117 elif self.
mouse[
"use"] ==
"query":
1119 if self.parent.IsStandalone():
1120 GMessage(parent = self.
parent,
1121 message = _(
"Querying is not implemented in standalone mode of Map Display"))
1126 self.parent.Query(self.
mouse[
'begin'][0],self.
mouse[
'begin'][1], layers)
1128 elif self.
mouse[
"use"]
in [
"measure",
"profile"]:
1130 if self.
mouse[
"use"] ==
"measure":
1131 self.parent.MeasureDist(self.
mouse[
'begin'], self.
mouse[
'end'])
1137 elif self.
mouse[
"use"] ==
"pointer" and \
1138 self.parent.GetLayerManager().gcpmanagement:
1140 if self.parent.GetToolbar(
'gcpdisp'):
1142 if self.parent.MapWindow == self.parent.SrcMapWindow:
1143 coordtype =
'source'
1145 coordtype =
'target'
1147 self.parent.GetLayerManager().gcpmanagement.SetGCPData(coordtype, coord, self, confirm =
True)
1148 self.
UpdateMap(render =
False, renderVector =
False)
1150 elif self.
mouse[
"use"] ==
"pointer" and \
1151 hasattr(self,
"digit"):
1152 self._onLeftUp(event)
1154 elif (self.
mouse[
'use'] ==
'pointer' and
1167 elif self.
mouse[
'use'] ==
'legend':
1168 self.parent.dialogs[
'legend'].resizeBtn.SetValue(
False)
1169 screenSize = self.GetClientSizeTuple()
1172 self.parent.MapWindow.SetCursor(self.parent.cursors[
"default"])
1173 self.parent.MapWindow.mouse[
'use'] =
'pointer'
1178 """!Mouse button double click
1180 Debug.msg (5,
"BufferedWindow.OnButtonDClick(): use=%s" % \
1183 if self.
mouse[
"use"] ==
"measure":
1187 self.
mouse[
'use'] =
'pointer'
1188 self.
mouse[
'box'] =
'point'
1189 self.
mouse[
'end'] = [0, 0]
1191 self.SetCursor(self.parent.cursors[
"default"])
1193 elif self.
mouse[
"use"] !=
"profile" or \
1194 (self.
mouse[
'use'] !=
'pointer' and \
1195 hasattr(self,
"digit")):
1197 clickposition = event.GetPositionTuple()[:]
1198 idlist = self.pdc.FindObjects(clickposition[0], clickposition[1], self.
hitradius)
1206 self.parent.OnAddText(
None)
1208 self.parent.AddBarscale()
1210 self.parent.AddLegend()
1213 """!Right mouse button pressed
1215 Debug.msg (5,
"BufferedWindow.OnRightDown(): use=%s" % \
1218 if hasattr(self,
"digit"):
1219 self._onRightDown(event)
1224 """!Right mouse button released
1226 Debug.msg (5,
"BufferedWindow.OnRightUp(): use=%s" % \
1229 if hasattr(self,
"digit"):
1230 self._onRightUp(event)
1238 """!Middle mouse button pressed
1243 self.
mouse[
'begin'] = event.GetPositionTuple()[:]
1246 """!Middle mouse button released
1248 self.
mouse[
'end'] = event.GetPositionTuple()[:]
1251 begin = self.
mouse[
'begin']
1252 end = self.
mouse[
'end']
1254 self.
Zoom(begin, end, 0)
1260 self.parent.StatusbarUpdate()
1263 """!Mouse entered window and no mouse buttons were pressed
1265 if self.parent.GetLayerManager().gcpmanagement:
1266 if self.parent.GetToolbar(
'gcpdisp'):
1267 if not self.parent.MapWindow == self:
1268 self.parent.MapWindow = self
1269 self.parent.Map = self.
Map
1270 self.parent.UpdateActive(self)
1277 """!Motion event and no mouse buttons were pressed
1279 if self.
mouse[
"use"] ==
"pointer" and \
1280 hasattr(self,
"digit"):
1281 self._onMouseMoving(event)
1286 """!Clears temporary drawn lines from PseudoDC
1292 pdc.RemoveId(self.
lineid)
1302 Debug.msg(4,
"BufferedWindow.ClearLines(): lineid=%s, plineid=%s" %
1308 """!Convert image coordinates to real word coordinates
1310 @param x, y image coordinates
1312 @return easting, northing
1313 @return None on error
1321 if self.Map.region[
"ewres"] > self.Map.region[
"nsres"]:
1322 res = self.Map.region[
"ewres"]
1324 res = self.Map.region[
"nsres"]
1326 w = self.Map.region[
"center_easting"] - (self.Map.width / 2) * res
1327 n = self.Map.region[
"center_northing"] + (self.Map.height / 2) * res
1332 return (east, north)
1335 """!Convert real word coordinates to image coordinates
1339 north = float(north)
1343 if self.Map.region[
"ewres"] > self.Map.region[
"nsres"]:
1344 res = self.Map.region[
"ewres"]
1346 res = self.Map.region[
"nsres"]
1348 w = self.Map.region[
"center_easting"] - (self.Map.width / 2) * res
1349 n = self.Map.region[
"center_northing"] + (self.Map.height / 2) * res
1351 x = (east - w) / res
1352 y = (n - north) / res
1356 def Zoom(self, begin, end, zoomtype):
1358 Calculates new region while (un)zoom/pan-ing
1366 if abs(x2-x1) > 5
and abs(y2-y1) > 5
and zoomtype != 0:
1374 newreg[
'w'], newreg[
'n'] = self.
Pixel2Cell((x1, y1))
1375 newreg[
'e'], newreg[
's'] = self.
Pixel2Cell((x2, y2))
1379 newreg[
'w'], newreg[
'n'] = self.
Pixel2Cell((-x1 * 2, -y1 * 2))
1380 newreg[
'e'], newreg[
's'] = self.
Pixel2Cell((self.Map.width + 2 * \
1381 (self.Map.width - x2),
1382 self.Map.height + 2 * \
1383 (self.Map.height - y2)))
1388 if dx == 0
and dy == 0:
1389 dx = x1 - self.Map.width / 2
1390 dy = y1 - self.Map.height / 2
1391 newreg[
'w'], newreg[
'n'] = self.
Pixel2Cell((dx, dy))
1392 newreg[
'e'], newreg[
's'] = self.
Pixel2Cell((self.Map.width + dx,
1393 self.Map.height + dy))
1398 if self.Map.projinfo[
'proj'] ==
'll':
1399 self.Map.region[
'n'] =
min(self.Map.region[
'n'], 90.0)
1400 self.Map.region[
's'] =
max(self.Map.region[
's'], -90.0)
1402 ce = newreg[
'w'] + (newreg[
'e'] - newreg[
'w']) / 2
1403 cn = newreg[
's'] + (newreg[
'n'] - newreg[
's']) / 2
1406 self.Map.region[
'center_easting'] = ce
1407 self.Map.region[
'center_northing'] = cn
1408 self.Map.region[
'ewres'] = (newreg[
'e'] - newreg[
'w']) / self.Map.width
1409 self.Map.region[
'nsres'] = (newreg[
'n'] - newreg[
's']) / self.Map.height
1410 if not self.parent.HasProperty(
'alignExtent')
or \
1411 self.parent.GetProperty(
'alignExtent'):
1412 self.Map.AlignExtentFromDisplay()
1414 for k
in (
'n',
's',
'e',
'w'):
1415 self.Map.region[k] = newreg[k]
1417 if hasattr(self,
"digit")
and \
1418 hasattr(self,
"moveInfo"):
1421 self.
ZoomHistory(self.Map.region[
'n'], self.Map.region[
's'],
1422 self.Map.region[
'e'], self.Map.region[
'w'])
1428 """!Zoom to previous extents in zoomhistory list
1433 self.zoomhistory.pop()
1438 toolbar = self.parent.GetMapToolbar()
1439 toolbar.Enable(
'zoomBack', enable =
False)
1442 self.Map.GetRegion(n = zoom[0], s = zoom[1],
1443 e = zoom[2], w = zoom[3],
1449 self.parent.StatusbarUpdate()
1452 """!Manages a list of last 10 zoom extents
1454 @param n,s,e,w north, south, east, west
1456 @return removed history item if exists (or None)
1459 self.zoomhistory.append((n,s,e,w))
1462 removed = self.zoomhistory.pop(0)
1465 Debug.msg(4,
"BufferedWindow.ZoomHistory(): hist=%s, removed=%s" %
1468 Debug.msg(4,
"BufferedWindow.ZoomHistory(): hist=%s" %
1477 toolbar = self.parent.GetMapToolbar()
1479 toolbar.Enable(
'zoomBack', enable)
1484 """!Reset zoom history"""
1487 def ZoomToMap(self, layers = None, ignoreNulls = False, render = True):
1488 """!Set display extents to match selected raster
1491 @param layers list of layers to be zoom to
1492 @param ignoreNulls True to ignore null-values (valid only for rasters)
1493 @param render True to re-render display
1508 if l.type ==
'raster':
1509 rast.append(l.GetName())
1510 elif l.type ==
'vector':
1511 if hasattr(self,
"digit")
and \
1512 self.toolbar.GetLayer() == l:
1513 w, s, b, e, n, t = self.digit.GetDisplay().GetMapBoundingBox()
1514 self.Map.GetRegion(n = n, s = s, w = w, e = e,
1519 elif l.type ==
'rgb':
1520 for rname
in l.GetName().splitlines():
1524 self.Map.GetRegion(rast = rast,
1528 self.
ZoomHistory(self.Map.region[
'n'], self.Map.region[
's'],
1529 self.Map.region[
'e'], self.Map.region[
'w'])
1534 self.parent.StatusbarUpdate()
1537 """!Set display geometry to match computational region
1538 settings (set with g.region)
1540 self.Map.region = self.Map.GetRegion()
1542 self.
ZoomHistory(self.Map.region[
'n'], self.Map.region[
's'],
1543 self.Map.region[
'e'], self.Map.region[
'w'])
1547 self.parent.StatusbarUpdate()
1550 """!Set display geometry to match default region settings
1552 self.Map.region = self.Map.GetRegion(default =
True)
1553 self.Map.AdjustRegion()
1555 self.
ZoomHistory(self.Map.region[
'n'], self.Map.region[
's'],
1556 self.Map.region[
'e'], self.Map.region[
'w'])
1560 self.parent.StatusbarUpdate()
1564 region = self.Map.GetCurrentRegion()
1566 region[
'center_easting'], region[
'center_northing'] = e, n
1568 dn = (region[
'nsres'] * region[
'rows']) / 2.
1569 region[
'n'] = region[
'center_northing'] + dn
1570 region[
's'] = region[
'center_northing'] - dn
1571 de = (region[
'ewres'] * region[
'cols']) / 2.
1572 region[
'e'] = region[
'center_easting'] + de
1573 region[
'w'] = region[
'center_easting'] - de
1575 self.Map.AdjustRegion()
1579 region[
'e'], region[
'w'])
1583 """!Set computational region (WIND file) to match display
1586 tmpreg = os.getenv(
"GRASS_REGION")
1588 del os.environ[
"GRASS_REGION"]
1592 new = self.Map.AlignResolution()
1600 rows = int(new[
'rows']),
1601 cols = int(new[
'cols']))
1604 os.environ[
"GRASS_REGION"] = tmpreg
1607 """!Set display geometry to match extents in
1610 dlg = SavedRegion(parent = self,
1611 title = _(
"Zoom to saved region extents"),
1614 if dlg.ShowModal() == wx.ID_CANCEL
or not dlg.wind:
1618 if not grass.find_file(name = dlg.wind, element =
'windows')[
'name']:
1619 wx.MessageBox(parent = self,
1620 message = _(
"Region <%s> not found. Operation canceled.") % dlg.wind,
1621 caption = _(
"Error"), style = wx.ICON_ERROR | wx.OK | wx.CENTRE)
1625 self.Map.GetRegion(regionName = dlg.wind,
1631 self.Map.region[
's'],
1632 self.Map.region[
'e'],
1633 self.Map.region[
'w'])
1638 """!Save display extents to named region file.
1640 dlg = SavedRegion(parent = self,
1641 title = _(
"Save display extents to region file"),
1644 if dlg.ShowModal() == wx.ID_CANCEL
or not dlg.wind:
1649 if grass.find_file(name = dlg.wind, element =
'windows')[
'name']:
1650 overwrite = wx.MessageBox(parent = self,
1651 message = _(
"Region file <%s> already exists. "
1652 "Do you want to overwrite it?") % (dlg.wind),
1653 caption = _(
"Warning"), style = wx.YES_NO | wx.CENTRE)
1654 if (overwrite == wx.YES):
1662 """!Save region settings
1664 @param wind region name
1666 new = self.Map.GetCurrentRegion()
1668 tmpreg = os.getenv(
"GRASS_REGION")
1670 del os.environ[
"GRASS_REGION"]
1680 rows = int(new[
'rows']),
1681 cols = int(new[
'cols']),
1685 os.environ[
"GRASS_REGION"] = tmpreg
1688 """!Calculete distance
1690 Ctypes required for LL-locations
1692 @param beginpt first point
1693 @param endpt second point
1694 @param screen True for screen coordinates otherwise EN
1706 if self.parent.Map.projinfo[
'proj'] ==
'll' and haveCtypes:
1707 dist = gislib.G_distance(e1, n1, e2, n2)
1709 dist = math.sqrt(math.pow((dEast), 2) + math.pow((dNorth), 2))
1711 return (dist, (dEast, dNorth))