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)
328 rgn = self.GetUpdateRegion().GetBox()
329 dc.SetClippingRect(rgn)
338 self.pdc.DrawToDCClipped(dc, rgn)
341 if hasattr(self,
"digit"):
345 self.pdcVector.DrawToDCClipped(gcdc, rgn)
346 except NotImplementedError, e:
347 print >> sys.stderr, e
348 self.pdcVector.DrawToDCClipped(dc, rgn)
354 self.pdc.DrawToDC(dc)
356 if hasattr(self,
"digit"):
360 self.pdcVector.DrawToDC(gcdc)
361 except NotImplementedError, e:
362 print >> sys.stderr, e
363 self.pdcVector.DrawToDC(dc)
367 self.
bufferLast = dc.GetAsBitmap(wx.Rect(0, 0, self.Map.width, self.Map.height))
369 self.pdc.DrawBitmap(self.
bufferLast, 0, 0,
False)
370 self.pdc.DrawToDC(dc)
375 self.pdcDec.DrawToDC(gcdc)
376 except NotImplementedError, e:
377 print >> sys.stderr, e
378 self.pdcDec.DrawToDC(dc)
382 self.pdcTmp.DrawToDC(dc)
388 """!Scale map image so that it is the same size as the Window
390 Debug.msg(3,
"BufferedWindow.OnSize():")
393 self.Map.ChangeMapSize(self.GetClientSize())
401 self.
buffer = wx.EmptyBitmap(
max(1, self.Map.width),
max(1, self.Map.height))
407 if self.
img and self.Map.width + self.Map.height > 0:
408 self.
img = self.img.Scale(self.Map.width, self.Map.height)
409 if len(self.Map.GetListOfLayers()) > 0:
416 self.parent.StatusbarReposition()
419 self.parent.StatusbarUpdate()
422 """!Only re-render a composite map image from GRASS during
423 idle time instead of multiple times during resizing.
431 """!This draws the pseudo DC to a buffer that can be saved to
434 @param FileName file name
435 @param FileType type of bitmap
436 @param width image width
437 @param height image height
439 busy = wx.BusyInfo(message = _(
"Please wait, exporting image..."),
443 self.Map.ChangeMapSize((width, height))
444 ibuffer = wx.EmptyBitmap(
max(1, width),
max(1, height))
445 self.Map.Render(force =
True, windres =
True)
448 self.
Draw(self.
pdc, img, drawid = 99)
451 cSize = self.GetClientSizeTuple()
452 ratio = float(width) / cSize[0], float(height) / cSize[1]
457 if self.
imagedict[img][
'layer'].IsActive():
459 coords = int(ratio[0] * self.
overlays[id].coords[0]),\
460 int(ratio[1] * self.
overlays[id].coords[1])
461 self.
Draw(self.
pdc, img = img, drawid = id,
462 pdctype = self.
overlays[id].pdcType, coords = coords)
465 for id
in self.textdict.keys():
467 oldCoords = textinfo[
'coords']
468 textinfo[
'coords'] = ratio[0] * textinfo[
'coords'][0],\
469 ratio[1] * textinfo[
'coords'][1]
473 textinfo[
'coords'] = oldCoords
475 dc = wx.BufferedDC(
None, ibuffer)
479 self.pdc.DrawToDC(dc)
481 self.pdcVector.DrawToDC(dc)
482 ibuffer.SaveFile(FileName, FileType)
490 """!Converts rendered overlay files to wx.Image
492 Updates self.imagedict
494 @return list of images
497 for overlay
in self.Map.GetListOfLayers(l_type =
"overlay", l_active =
True):
498 if overlay.mapfile
is not None \
499 and os.path.isfile(overlay.mapfile)
and os.path.getsize(overlay.mapfile):
500 img = wx.Image(overlay.mapfile, wx.BITMAP_TYPE_ANY)
502 for key
in self.imagedict.keys():
503 if self.
imagedict[key][
'id'] == overlay.id:
506 self.
imagedict[img] = {
'id' : overlay.id,
513 """!Converts redered map files to wx.Image
515 Updates self.imagedict (id=99)
517 @return wx.Image instance (map composition)
520 if self.
mapfile and self.Map.mapfile
and os.path.isfile(self.Map.mapfile)
and \
521 os.path.getsize(self.Map.mapfile):
522 img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
526 for key
in self.imagedict.keys():
534 def UpdateMap(self, render = True, renderVector = True):
535 """!Updates the canvas anytime there is a change to the
536 underlaying images or to the geometry of the canvas.
538 @param render re-render map composition
539 @param renderVector re-render vector map layer enabled for editing (used for digitizer)
551 if render
or renderVector:
552 self.parent.GetProgressBar().Show()
553 if self.parent.GetProgressBar().GetRange() > 0:
554 self.parent.GetProgressBar().
SetValue(1)
560 if self.
tree and self.tree.reorder:
561 self.tree.ReorderLayers()
565 self.tree.rerender =
False
570 self.Map.ChangeMapSize(self.GetClientSize())
571 if self.parent.GetProperty(
'resolution'):
576 self.
mapfile = self.Map.Render(force =
True, mapWindow = self.
parent,
579 self.
mapfile = self.Map.Render(force =
False, mapWindow = self.
parent)
580 except GException, e:
581 GError(message = e.value)
589 for pdc
in (self.
pdc,
599 self.
Draw(self.
pdc, pdctype =
'clear')
611 if renderVector
and hasattr(self,
"digit"):
618 if self.
imagedict[img][
'layer'].IsActive():
620 self.
Draw(self.
pdc, img = img, drawid = id,
623 for id
in self.textdict.keys():
625 pdctype =
'text', coords = [10, 10, 10, 10])
636 if not self.parent.IsStandalone()
and \
637 self.parent.GetLayerManager().gcpmanagement:
639 if self.parent.GetMapToolbar():
640 if self == self.parent.TgtMapWindow:
645 self.parent.DrawGCP(coordtype)
650 if self.
mouse[
"use"] ==
"measure":
653 self.
mouse[
'use'] =
'pointer'
654 self.
mouse[
'box'] =
'point'
655 self.
mouse[
'end'] = [0, 0]
656 self.SetCursor(self.parent.cursors[
"default"])
663 self.parent.GetProgressBar().Hide()
669 self.parent.StatusbarUpdate()
671 Debug.msg (1,
"BufferedWindow.UpdateMap(): render=%s, renderVector=%s -> time=%g" % \
672 (render, renderVector, (stop-start)))
677 """!Draw computational region extent in the display
679 Display region is drawn as a blue box inside the computational region,
680 computational region inside a display region as a red box).
682 if hasattr(self,
"regionCoords"):
683 compReg = self.Map.GetRegion()
684 dispReg = self.Map.GetCurrentRegion()
687 self.
polypen = wx.Pen(colour = wx.Colour(0, 0, 255, 128), width = 3, style = wx.SOLID)
690 self.
polypen = wx.Pen(colour = wx.Colour(255, 0, 0, 128),
691 width = 3, style = wx.SOLID)
695 self.regionCoords.append((reg[
'w'], reg[
'n']))
696 self.regionCoords.append((reg[
'e'], reg[
'n']))
697 self.regionCoords.append((reg[
'e'], reg[
's']))
698 self.regionCoords.append((reg[
'w'], reg[
's']))
699 self.regionCoords.append((reg[
'w'], reg[
'n']))
705 Test if 'region' is inside of 'refRegion'
707 @param region input region
708 @param refRegion reference region (e.g. computational region)
710 @return True if region is inside of refRegion
713 if region[
's'] >= refRegion[
's']
and \
714 region[
'n'] <= refRegion[
'n']
and \
715 region[
'w'] >= refRegion[
'w']
and \
716 region[
'e'] <= refRegion[
'e']:
724 self.
Draw(self.
pdc, pdctype =
'clear')
726 if hasattr(self,
"digit"):
733 """!Drag the entire map image for panning.
737 dc = wx.BufferedDC(wx.ClientDC(self))
738 dc.SetBackground(wx.Brush(
"White"))
742 self.dragimg.BeginDrag((0, 0), self)
743 self.dragimg.GetImageRect(moveto)
744 self.dragimg.Move(moveto)
746 self.dragimg.DoDrawImage(dc, moveto)
747 self.dragimg.EndDrag()
750 """!Drag an overlay decoration item
752 if id == 99
or id ==
'' or id ==
None:
return
753 Debug.msg (5,
"BufferedWindow.DragItem(): id=%d" % id)
755 dx = event.GetX() - x
756 dy = event.GetY() - y
757 self.pdc.SetBackground(wx.Brush(self.GetBackgroundColour()))
758 r = self.pdc.GetIdBounds(id)
760 r = wx.Rect(r[0], r[1], r[2], r[3])
762 rtop = (r[0],r[1]-r[3],r[2],r[3])
764 rleft = (r[0]-r[2],r[1],r[2],r[3])
766 self.pdc.TranslateId(id, dx, dy)
768 r2 = self.pdc.GetIdBounds(id)
770 r2 = wx.Rect(r[0], r[1], r[2], r[3])
773 self.
textdict[id][
'coords'][0] += dx
774 self.
textdict[id][
'coords'][1] += dy
777 self.RefreshRect(r,
False)
778 self.
lastpos = (event.GetX(), event.GetY())
780 def MouseDraw(self, pdc = None, begin = None, end = None):
781 """!Mouse box or line from 'begin' to 'end'
783 If not given from self.mouse['begin'] to self.mouse['end'].
789 begin = self.
mouse[
'begin']
791 end = self.
mouse[
'end']
793 Debug.msg (5,
"BufferedWindow.MouseDraw(): use=%s, box=%s, begin=%f,%f, end=%f,%f" % \
795 begin[0], begin[1], end[0], end[1]))
797 if self.
mouse[
'box'] ==
"box":
799 mousecoords = [begin[0], begin[1],
801 r = pdc.GetIdBounds(boxid)
803 r = wx.Rect(r[0], r[1], r[2], r[3])
809 self.RefreshRect(r,
False)
811 self.
Draw(pdc, drawid = boxid, pdctype =
'box', coords = mousecoords)
813 elif self.
mouse[
'box'] ==
"line":
815 mousecoords = [begin[0], begin[1], \
817 x1 =
min(begin[0],end[0])
818 x2 =
max(begin[0],end[0])
819 y1 =
min(begin[1],end[1])
820 y2 =
max(begin[1],end[1])
821 r = wx.Rect(x1,y1,x2-x1,y2-y1)
827 self.RefreshRect(r,
False)
829 self.
Draw(pdc, drawid = self.
lineid, pdctype =
'line', coords = mousecoords)
832 """!Draw polyline in PseudoDC
834 Set self.pline to wx.NEW_ID + 1
836 polycoords - list of polyline vertices, geographical coordinates
837 (if not given, self.polycoords is used)
845 if len(polycoords) > 0:
852 self.
Draw(pdc, drawid = self.
plineid, pdctype =
'polyline', coords = coords)
854 Debug.msg (4,
"BufferedWindow.DrawLines(): coords=%s, id=%s" % \
861 def DrawCross(self, pdc, coords, size, rotation = 0,
862 text =
None, textAlign =
'lr', textOffset = (5, 5)):
863 """!Draw cross in PseudoDC
865 @todo implement rotation
868 @param coord center coordinates
869 @param rotation rotate symbol
870 @param text draw also text (text, font, color, rotation)
871 @param textAlign alignment (default 'lower-right')
872 @textOffset offset for text (from center point)
874 Debug.msg(4,
"BufferedWindow.DrawCross(): pdc=%s, coords=%s, size=%d" % \
876 coordsCross = ((coords[0] - size, coords[1], coords[0] + size, coords[1]),
877 (coords[0], coords[1] - size, coords[0], coords[1] + size))
880 for lineCoords
in coordsCross:
881 self.
Draw(pdc, drawid = self.
lineid, pdctype =
'line', coords = lineCoords)
886 if textAlign ==
'ul':
887 coord = [coords[0] - textOffset[0], coords[1] - textOffset[1], 0, 0]
888 elif textAlign ==
'ur':
889 coord = [coords[0] + textOffset[0], coords[1] - textOffset[1], 0, 0]
890 elif textAlign ==
'lr':
891 coord = [coords[0] + textOffset[0], coords[1] + textOffset[1], 0, 0]
893 coord = [coords[0] - textOffset[0], coords[1] + textOffset[1], 0, 0]
895 self.
Draw(pdc, img = text,
896 pdctype =
'text', coords = coord)
900 def _computeZoomToPointAndRecenter(self, position, zoomtype):
901 """!Computes zoom parameters for recenter mode.
903 Computes begin and end parameters for Zoom() method.
904 Used for zooming by single click (not box)
905 and mouse wheel zooming (zoom and recenter mode).
908 begin = (position[0] - self.Map.width / 4,
909 position[1] - self.Map.height / 4)
910 end = (position[0] + self.Map.width / 4,
911 position[1] + self.Map.height / 4)
913 begin = ((self.Map.width - position[0]) / 2,
914 (self.Map.height - position[1]) / 2)
915 end = (begin[0] + self.Map.width / 2,
916 begin[1] + self.Map.height / 2)
920 """!Mouse motion and button click notifier
926 if event.GetWheelRotation() != 0:
930 elif event.LeftDown():
938 elif event.Dragging():
942 elif event.ButtonDClick():
946 elif event.MiddleDown():
950 elif event.MiddleUp():
954 elif event.RightDown():
958 elif event.RightUp():
961 elif event.Entering():
968 """!Mouse wheel moved
970 zoomBehaviour = UserSettings.Get(group =
'display',
971 key =
'mouseWheelZoom',
972 subkey =
'selection')
973 if zoomBehaviour == 2:
978 current = event.GetPositionTuple()[:]
979 wheel = event.GetWheelRotation()
980 Debug.msg (5,
"BufferedWindow.MouseAction(): wheel=%d" % wheel)
986 if UserSettings.Get(group =
'display',
987 key =
'scrollDirection',
988 subkey =
'selection'):
991 if zoomBehaviour == 0:
994 elif zoomBehaviour == 1:
995 begin = (current[0]/2, current[1]/2)
996 end = ((self.Map.width - current[0])/2 + current[0],
997 (self.Map.height - current[1])/2 + current[1])
1000 self.
Zoom(begin, end, zoomtype)
1006 self.parent.StatusbarUpdate()
1014 Debug.msg (5,
"BufferedWindow.MouseAction(): Dragging")
1015 current = event.GetPositionTuple()[:]
1016 previous = self.
mouse[
'begin']
1017 move = (current[0] - previous[0],
1018 current[1] - previous[1])
1020 if hasattr(self,
"digit"):
1021 digitToolbar = self.toolbar
1026 if self.
mouse[
'use'] ==
'pan' or \
1027 event.MiddleIsDown():
1031 elif (self.
mouse[
'use'] ==
'pointer' and
1032 not digitToolbar
and
1038 if (self.
mouse[
'use'] ==
'pointer' and
1042 self.
mouse[
'end'] = event.GetPositionTuple()[:]
1043 if (event.LeftIsDown()
and
1044 not (digitToolbar
and
1045 digitToolbar.GetAction()
in (
"moveLine",)
and
1046 self.digit.GetDisplay().GetSelected() > 0)):
1050 """!Left mouse button pressed
1052 Debug.msg (5,
"BufferedWindow.OnLeftDown(): use=%s" % \
1055 self.
mouse[
'begin'] = event.GetPositionTuple()[:]
1057 if self.
mouse[
"use"]
in [
"measure",
"profile"]:
1066 elif self.
mouse[
'use']
in (
'zoom',
'legend'):
1070 elif self.
mouse[
"use"] ==
"pointer" and \
1071 hasattr(self,
"digit"):
1072 if event.ControlDown():
1073 self.OnLeftDownUndo(event)
1075 self._onLeftDown(event)
1077 elif self.
mouse[
'use'] ==
'pointer':
1094 """!Left mouse button released
1096 Debug.msg (5,
"BufferedWindow.OnLeftUp(): use=%s" % \
1099 self.
mouse[
'end'] = event.GetPositionTuple()[:]
1101 if self.
mouse[
'use']
in [
"zoom",
"pan"]:
1103 begin = self.
mouse[
'begin']
1104 end = self.
mouse[
'end']
1106 if self.
mouse[
'use'] ==
'zoom':
1108 if begin[0] - end[0] == 0
or \
1109 begin[1] - end[1] == 0:
1117 self.parent.StatusbarUpdate()
1119 elif self.
mouse[
"use"] ==
"query":
1121 if self.parent.IsStandalone():
1122 GMessage(parent = self.
parent,
1123 message = _(
"Querying is not implemented in standalone mode of Map Display"))
1128 self.parent.Query(self.
mouse[
'begin'][0],self.
mouse[
'begin'][1], layers)
1130 elif self.
mouse[
"use"]
in [
"measure",
"profile"]:
1132 if self.
mouse[
"use"] ==
"measure":
1133 self.parent.MeasureDist(self.
mouse[
'begin'], self.
mouse[
'end'])
1139 elif self.
mouse[
"use"] ==
"pointer" and \
1140 self.parent.GetLayerManager().gcpmanagement:
1142 if self.parent.GetToolbar(
'gcpdisp'):
1144 if self.parent.MapWindow == self.parent.SrcMapWindow:
1145 coordtype =
'source'
1147 coordtype =
'target'
1149 self.parent.GetLayerManager().gcpmanagement.SetGCPData(coordtype, coord, self, confirm =
True)
1150 self.
UpdateMap(render =
False, renderVector =
False)
1152 elif self.
mouse[
"use"] ==
"pointer" and \
1153 hasattr(self,
"digit"):
1154 self._onLeftUp(event)
1156 elif (self.
mouse[
'use'] ==
'pointer' and
1169 elif self.
mouse[
'use'] ==
'legend':
1170 self.parent.dialogs[
'legend'].resizeBtn.SetValue(
False)
1171 screenSize = self.GetClientSizeTuple()
1174 self.parent.MapWindow.SetCursor(self.parent.cursors[
"default"])
1175 self.parent.MapWindow.mouse[
'use'] =
'pointer'
1180 """!Mouse button double click
1182 Debug.msg (5,
"BufferedWindow.OnButtonDClick(): use=%s" % \
1185 if self.
mouse[
"use"] ==
"measure":
1189 self.
mouse[
'use'] =
'pointer'
1190 self.
mouse[
'box'] =
'point'
1191 self.
mouse[
'end'] = [0, 0]
1193 self.SetCursor(self.parent.cursors[
"default"])
1195 elif self.
mouse[
"use"] !=
"profile" or \
1196 (self.
mouse[
'use'] !=
'pointer' and \
1197 hasattr(self,
"digit")):
1199 clickposition = event.GetPositionTuple()[:]
1200 idlist = self.pdc.FindObjects(clickposition[0], clickposition[1], self.
hitradius)
1208 self.parent.OnAddText(
None)
1210 self.parent.AddBarscale()
1212 self.parent.AddLegend()
1215 """!Right mouse button pressed
1217 Debug.msg (5,
"BufferedWindow.OnRightDown(): use=%s" % \
1220 if hasattr(self,
"digit"):
1221 self._onRightDown(event)
1226 """!Right mouse button released
1228 Debug.msg (5,
"BufferedWindow.OnRightUp(): use=%s" % \
1231 if hasattr(self,
"digit"):
1232 self._onRightUp(event)
1240 """!Middle mouse button pressed
1245 self.
mouse[
'begin'] = event.GetPositionTuple()[:]
1248 """!Middle mouse button released
1250 self.
mouse[
'end'] = event.GetPositionTuple()[:]
1253 begin = self.
mouse[
'begin']
1254 end = self.
mouse[
'end']
1256 self.
Zoom(begin, end, 0)
1262 self.parent.StatusbarUpdate()
1265 """!Mouse entered window and no mouse buttons were pressed
1267 if self.parent.GetLayerManager().gcpmanagement:
1268 if self.parent.GetToolbar(
'gcpdisp'):
1269 if not self.parent.MapWindow == self:
1270 self.parent.MapWindow = self
1271 self.parent.Map = self.
Map
1272 self.parent.UpdateActive(self)
1279 """!Motion event and no mouse buttons were pressed
1281 if self.
mouse[
"use"] ==
"pointer" and \
1282 hasattr(self,
"digit"):
1283 self._onMouseMoving(event)
1288 """!Clears temporary drawn lines from PseudoDC
1294 pdc.RemoveId(self.
lineid)
1304 Debug.msg(4,
"BufferedWindow.ClearLines(): lineid=%s, plineid=%s" %
1310 """!Convert image coordinates to real word coordinates
1312 @param x, y image coordinates
1314 @return easting, northing
1315 @return None on error
1323 if self.Map.region[
"ewres"] > self.Map.region[
"nsres"]:
1324 res = self.Map.region[
"ewres"]
1326 res = self.Map.region[
"nsres"]
1328 w = self.Map.region[
"center_easting"] - (self.Map.width / 2) * res
1329 n = self.Map.region[
"center_northing"] + (self.Map.height / 2) * res
1334 return (east, north)
1337 """!Convert real word coordinates to image coordinates
1341 north = float(north)
1345 if self.Map.region[
"ewres"] > self.Map.region[
"nsres"]:
1346 res = self.Map.region[
"ewres"]
1348 res = self.Map.region[
"nsres"]
1350 w = self.Map.region[
"center_easting"] - (self.Map.width / 2) * res
1351 n = self.Map.region[
"center_northing"] + (self.Map.height / 2) * res
1353 x = (east - w) / res
1354 y = (n - north) / res
1358 def Zoom(self, begin, end, zoomtype):
1360 Calculates new region while (un)zoom/pan-ing
1368 if abs(x2-x1) > 5
and abs(y2-y1) > 5
and zoomtype != 0:
1376 newreg[
'w'], newreg[
'n'] = self.
Pixel2Cell((x1, y1))
1377 newreg[
'e'], newreg[
's'] = self.
Pixel2Cell((x2, y2))
1381 newreg[
'w'], newreg[
'n'] = self.
Pixel2Cell((-x1 * 2, -y1 * 2))
1382 newreg[
'e'], newreg[
's'] = self.
Pixel2Cell((self.Map.width + 2 * \
1383 (self.Map.width - x2),
1384 self.Map.height + 2 * \
1385 (self.Map.height - y2)))
1390 if dx == 0
and dy == 0:
1391 dx = x1 - self.Map.width / 2
1392 dy = y1 - self.Map.height / 2
1393 newreg[
'w'], newreg[
'n'] = self.
Pixel2Cell((dx, dy))
1394 newreg[
'e'], newreg[
's'] = self.
Pixel2Cell((self.Map.width + dx,
1395 self.Map.height + dy))
1400 if self.Map.projinfo[
'proj'] ==
'll':
1401 self.Map.region[
'n'] =
min(self.Map.region[
'n'], 90.0)
1402 self.Map.region[
's'] =
max(self.Map.region[
's'], -90.0)
1404 ce = newreg[
'w'] + (newreg[
'e'] - newreg[
'w']) / 2
1405 cn = newreg[
's'] + (newreg[
'n'] - newreg[
's']) / 2
1408 self.Map.region[
'center_easting'] = ce
1409 self.Map.region[
'center_northing'] = cn
1410 self.Map.region[
'ewres'] = (newreg[
'e'] - newreg[
'w']) / self.Map.width
1411 self.Map.region[
'nsres'] = (newreg[
'n'] - newreg[
's']) / self.Map.height
1412 if not self.parent.HasProperty(
'alignExtent')
or \
1413 self.parent.GetProperty(
'alignExtent'):
1414 self.Map.AlignExtentFromDisplay()
1416 for k
in (
'n',
's',
'e',
'w'):
1417 self.Map.region[k] = newreg[k]
1419 if hasattr(self,
"digit")
and \
1420 hasattr(self,
"moveInfo"):
1423 self.
ZoomHistory(self.Map.region[
'n'], self.Map.region[
's'],
1424 self.Map.region[
'e'], self.Map.region[
'w'])
1430 """!Zoom to previous extents in zoomhistory list
1435 self.zoomhistory.pop()
1440 toolbar = self.parent.GetMapToolbar()
1441 toolbar.Enable(
'zoomBack', enable =
False)
1444 self.Map.GetRegion(n = zoom[0], s = zoom[1],
1445 e = zoom[2], w = zoom[3],
1451 self.parent.StatusbarUpdate()
1454 """!Manages a list of last 10 zoom extents
1456 @param n,s,e,w north, south, east, west
1458 @return removed history item if exists (or None)
1461 self.zoomhistory.append((n,s,e,w))
1464 removed = self.zoomhistory.pop(0)
1467 Debug.msg(4,
"BufferedWindow.ZoomHistory(): hist=%s, removed=%s" %
1470 Debug.msg(4,
"BufferedWindow.ZoomHistory(): hist=%s" %
1479 toolbar = self.parent.GetMapToolbar()
1481 toolbar.Enable(
'zoomBack', enable)
1486 """!Reset zoom history"""
1489 def ZoomToMap(self, layers = None, ignoreNulls = False, render = True):
1490 """!Set display extents to match selected raster
1493 @param layers list of layers to be zoom to
1494 @param ignoreNulls True to ignore null-values (valid only for rasters)
1495 @param render True to re-render display
1510 if l.type ==
'raster':
1511 rast.append(l.GetName())
1512 elif l.type ==
'vector':
1513 if hasattr(self,
"digit")
and \
1514 self.toolbar.GetLayer() == l:
1515 w, s, b, e, n, t = self.digit.GetDisplay().GetMapBoundingBox()
1516 self.Map.GetRegion(n = n, s = s, w = w, e = e,
1521 elif l.type ==
'rgb':
1522 for rname
in l.GetName().splitlines():
1526 self.Map.GetRegion(rast = rast,
1530 self.
ZoomHistory(self.Map.region[
'n'], self.Map.region[
's'],
1531 self.Map.region[
'e'], self.Map.region[
'w'])
1536 self.parent.StatusbarUpdate()
1539 """!Set display geometry to match computational region
1540 settings (set with g.region)
1542 self.Map.region = self.Map.GetRegion()
1544 self.
ZoomHistory(self.Map.region[
'n'], self.Map.region[
's'],
1545 self.Map.region[
'e'], self.Map.region[
'w'])
1549 self.parent.StatusbarUpdate()
1552 """!Set display geometry to match default region settings
1554 self.Map.region = self.Map.GetRegion(default =
True)
1555 self.Map.AdjustRegion()
1557 self.
ZoomHistory(self.Map.region[
'n'], self.Map.region[
's'],
1558 self.Map.region[
'e'], self.Map.region[
'w'])
1562 self.parent.StatusbarUpdate()
1566 region = self.Map.GetCurrentRegion()
1568 region[
'center_easting'], region[
'center_northing'] = e, n
1570 dn = (region[
'nsres'] * region[
'rows']) / 2.
1571 region[
'n'] = region[
'center_northing'] + dn
1572 region[
's'] = region[
'center_northing'] - dn
1573 de = (region[
'ewres'] * region[
'cols']) / 2.
1574 region[
'e'] = region[
'center_easting'] + de
1575 region[
'w'] = region[
'center_easting'] - de
1577 self.Map.AdjustRegion()
1581 region[
'e'], region[
'w'])
1585 """!Set computational region (WIND file) to match display
1588 tmpreg = os.getenv(
"GRASS_REGION")
1590 del os.environ[
"GRASS_REGION"]
1594 new = self.Map.AlignResolution()
1602 rows = int(new[
'rows']),
1603 cols = int(new[
'cols']))
1606 os.environ[
"GRASS_REGION"] = tmpreg
1609 """!Set display geometry to match extents in
1612 dlg = SavedRegion(parent = self,
1613 title = _(
"Zoom to saved region extents"),
1616 if dlg.ShowModal() == wx.ID_CANCEL
or not dlg.wind:
1620 if not grass.find_file(name = dlg.wind, element =
'windows')[
'name']:
1621 wx.MessageBox(parent = self,
1622 message = _(
"Region <%s> not found. Operation canceled.") % dlg.wind,
1623 caption = _(
"Error"), style = wx.ICON_ERROR | wx.OK | wx.CENTRE)
1627 self.Map.GetRegion(regionName = dlg.wind,
1633 self.Map.region[
's'],
1634 self.Map.region[
'e'],
1635 self.Map.region[
'w'])
1640 """!Save display extents to named region file.
1642 dlg = SavedRegion(parent = self,
1643 title = _(
"Save display extents to region file"),
1646 if dlg.ShowModal() == wx.ID_CANCEL
or not dlg.wind:
1651 if grass.find_file(name = dlg.wind, element =
'windows')[
'name']:
1652 overwrite = wx.MessageBox(parent = self,
1653 message = _(
"Region file <%s> already exists. "
1654 "Do you want to overwrite it?") % (dlg.wind),
1655 caption = _(
"Warning"), style = wx.YES_NO | wx.CENTRE)
1656 if (overwrite == wx.YES):
1664 """!Save region settings
1666 @param wind region name
1668 new = self.Map.GetCurrentRegion()
1670 tmpreg = os.getenv(
"GRASS_REGION")
1672 del os.environ[
"GRASS_REGION"]
1682 rows = int(new[
'rows']),
1683 cols = int(new[
'cols']),
1687 os.environ[
"GRASS_REGION"] = tmpreg
1690 """!Calculete distance
1692 Ctypes required for LL-locations
1694 @param beginpt first point
1695 @param endpt second point
1696 @param screen True for screen coordinates otherwise EN
1708 if self.parent.Map.projinfo[
'proj'] ==
'll' and haveCtypes:
1709 dist = gislib.G_distance(e1, n1, e2, n2)
1711 dist = math.sqrt(math.pow((dEast), 2) + math.pow((dNorth), 2))
1713 return (dist, (dEast, dNorth))
def ZoomToSaved
Set display geometry to match extents in saved region file.
def OnLeftUp
Left mouse button released.
def DrawLines
Draw polyline in PseudoDC.
def OnDragging
Mouse dragging.
Abstract map display window class.
def OnButtonDClick
Mouse button double click.
def ZoomBack
Zoom to previous extents in zoomhistory list.
def ZoomToMap
Set display extents to match selected raster or vector map(s).
def OnIdle
Only re-render a composite map image from GRASS during idle time instead of multiple times during res...
def OnMiddleUp
Middle mouse button released.
def DrawCompRegionExtent
Draw computational region extent in the display.
def GetSelectedLayer
Get selected layer from layer tree.
Map display canvas - base class for buffered window.
def OnLeftDown
Left mouse button pressed.
def OnMotion
Tracks mouse motion and update statusbar.
redrawAll
self.OnSize(None)
def _definePseudoDC
Define PseudoDC objects to use.
def DrawCross
Draw cross in PseudoDC.
def ZoomHistory
Manages a list of last 10 zoom extents.
def SaveDisplayRegion
Save display extents to named region file.
def Zoom
Calculates new region while (un)zoom/pan-ing.
def OnMouseEnter
Mouse entered window and no mouse buttons were pressed.
def OnPaint
Draw PseudoDC's to buffered paint DC.
Various dialogs used in wxGUI.
def UpdateMap
Updates the canvas anytime there is a change to the underlaying images or to the geometry of the canv...
def DisplayToWind
Set computational region (WIND file) to match display extents.
def ResetZoomHistory
Reset zoom history.
def OnSize
Scale map image so that it is the same size as the Window.
def GetOverlay
Converts rendered overlay files to wx.Image.
def IsInRegion
Test if 'region' is inside of 'refRegion'.
buffer
self.Map.AlignExtentFromDisplay()
def EraseMap
Erase map canvas.
def SaveRegion
Save region settings.
def GetImage
Converts redered map files to wx.Image.
def Pixel2Cell
Convert image coordinates to real word coordinates.
def MouseActions
Mouse motion and button click notifier.
def TextBounds
Return text boundary data.
def SaveToFile
This draws the pseudo DC to a buffer that can be saved to a file.
def DragItem
Drag an overlay decoration item.
def OnMouseMoving
Motion event and no mouse buttons were pressed.
def Draw
Draws map and overlay decorations.
def OnRightUp
Right mouse button released.
def ZoomToWind
Set display geometry to match computational region settings (set with g.region)
def Cell2Pixel
Convert real word coordinates to image coordinates.
def Distance
Calculete distance.
def OnMiddleDown
Middle mouse button pressed.
def MouseDraw
Mouse box or line from 'begin' to 'end'.
def _computeZoomToPointAndRecenter
Computes zoom parameters for recenter mode.
def OnMouseWheel
Mouse wheel moved.
A Buffered window class (2D view mode)
def DragMap
Drag the entire map image for panning.
def ZoomToDefault
Set display geometry to match default region settings.
def RunCommand
Run GRASS command.
def ClearLines
Clears temporary drawn lines from PseudoDC.
def OnRightDown
Right mouse button pressed.