[GRASS-SVN] r31845 - in grass-addons/visualization/nviz2/wxpython: . nviz

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Jun 25 16:47:37 EDT 2008


Author: martinl
Date: 2008-06-25 16:47:36 -0400 (Wed, 25 Jun 2008)
New Revision: 31845

Modified:
   grass-addons/visualization/nviz2/wxpython/mapdisp.py
   grass-addons/visualization/nviz2/wxpython/nviz.py
   grass-addons/visualization/nviz2/wxpython/nviz/change_view.cpp
   grass-addons/visualization/nviz2/wxpython/nviz/draw.cpp
   grass-addons/visualization/nviz2/wxpython/nviz/init.cpp
   grass-addons/visualization/nviz2/wxpython/nviz/nviz.h
Log:
nviz2: wxGUI integration improvements

Modified: grass-addons/visualization/nviz2/wxpython/mapdisp.py
===================================================================
--- grass-addons/visualization/nviz2/wxpython/mapdisp.py	2008-06-25 18:04:38 UTC (rev 31844)
+++ grass-addons/visualization/nviz2/wxpython/mapdisp.py	2008-06-25 20:47:36 UTC (rev 31845)
@@ -157,6 +157,27 @@
     def OnMouseMotion(self, event):
         pass
 
+    def ZoomToMap(self, event):
+        pass
+
+    def GetSelectedLayer(self):
+        """Get selected layer from layer tree
+
+        @return map layer instance
+        @return None on failure
+        """
+        # get currently selected map layer
+        if not self.tree or not self.tree.GetSelection():
+            return None
+        
+        item = self.tree.GetSelection()
+        try:
+            layer = self.tree.GetPyData(item)[0]['maplayer']
+        except:
+            layer = None
+            
+        return layer
+
 class BufferedWindow(MapWindow, wx.Window):
     """
     A Buffered window class.
@@ -2075,16 +2096,8 @@
         """
         zoomreg = {}
 
-        # find selected map
-        if not self.tree or not self.tree.GetSelection():
-            return
+        layer = self.GetSelectedLayer()
 
-        item  = self.tree.GetSelection()
-        try:
-            layer = self.tree.GetPyData(item)[0]['maplayer']
-        except:
-            layer = None
-
         if layer is None:
             return
 
@@ -2545,13 +2558,16 @@
             #
             if not self.MapWindow3D:
                 self.MapWindow3D = nviz.GLWindow(self, id=wx.ID_ANY,
-                                             Map=self.Map, tree=self.tree, gismgr=self.gismanager)
+                                                 Map=self.Map, tree=self.tree, gismgr=self.gismanager)
+                self.nvizToolWin = nviz.NvizToolWindow(self, id=wx.ID_ANY,
+                                                       settings=self.MapWindow3D.view)
             
             #
             # add Nviz toolbar and disable 2D display mode tools
             #
             self.toolbars['nviz'] = toolbars.NvizToolbar(self, self.Map)
             self.toolbars['map'].Enable2D(False)
+            self.nvizToolWin.Show()
 
             #
             # switch from MapWindow to MapWindowGL
@@ -2596,6 +2612,8 @@
         self.toolbars[name] = None
 
         if name == 'nviz':
+            # hide nviz tools
+            self.nvizToolWin.Hide()
             # unload data
             self.MapWindow3D.Reset()
             # switch from MapWindowGL to MapWindow

Modified: grass-addons/visualization/nviz2/wxpython/nviz/change_view.cpp
===================================================================
--- grass-addons/visualization/nviz2/wxpython/nviz/change_view.cpp	2008-06-25 18:04:38 UTC (rev 31844)
+++ grass-addons/visualization/nviz2/wxpython/nviz/change_view.cpp	2008-06-25 20:47:36 UTC (rev 31845)
@@ -32,22 +32,49 @@
     return Nviz_resize_window(width, height);
 }
 
-void Nviz::SetViewportDefault()
+/*!
+  \brief Set default view (based on loaded data)
+
+  \return height value
+*/
+float Nviz::SetViewDefault()
 {
     float vp_height;
+
     /* determine height */
     Nviz_get_exag_height(&vp_height, NULL, NULL);
 
-    Nviz_set_viewpoint_height(data,
-			      vp_height);
     Nviz_change_exag(data,
 		     1.0);
+
+    SetView(0.85, 0.85,
+	    vp_height, 40.0, 0.0);
+
+    return vp_height;
+}
+
+/*!
+  \brief Change view settings
+
+  \param x,y position
+  \param height
+  \param persp perpective
+  \param twist
+
+  \return 1 on success
+  \return 0 on failure
+*/
+int Nviz::SetView(float x, float y,
+		  float height, float persp, float twist)
+{
+    Nviz_set_viewpoint_height(data,
+			      height);
     Nviz_set_viewpoint_position(data,
-				0.85, 0.85);
+				x, y);
     Nviz_set_viewpoint_twist(data,
-			     0.0);
+			     twist);
     Nviz_set_viewpoint_persp(data,
-			     40);
+			     persp);
 
-    return;
+    return 1;
 }

Modified: grass-addons/visualization/nviz2/wxpython/nviz/draw.cpp
===================================================================
--- grass-addons/visualization/nviz2/wxpython/nviz/draw.cpp	2008-06-25 18:04:38 UTC (rev 31844)
+++ grass-addons/visualization/nviz2/wxpython/nviz/draw.cpp	2008-06-25 20:47:36 UTC (rev 31845)
@@ -22,7 +22,7 @@
 void Nviz::Draw()
 {
     GS_clear(data->bgcolor);
-
+    
     Nviz_draw_cplane(data, -1, -1);
     Nviz_draw_all (data);
 

Modified: grass-addons/visualization/nviz2/wxpython/nviz/init.cpp
===================================================================
--- grass-addons/visualization/nviz2/wxpython/nviz/init.cpp	2008-06-25 18:04:38 UTC (rev 31844)
+++ grass-addons/visualization/nviz2/wxpython/nviz/init.cpp	2008-06-25 20:47:36 UTC (rev 31845)
@@ -26,6 +26,8 @@
 {
     G_gisinit(""); /* GRASS functions */
 
+    G_set_verbose(0); // TODO: read progress info
+
     GS_libinit();
     /* GVL_libinit(); TODO */
 

Modified: grass-addons/visualization/nviz2/wxpython/nviz/nviz.h
===================================================================
--- grass-addons/visualization/nviz2/wxpython/nviz/nviz.h	2008-06-25 18:04:38 UTC (rev 31844)
+++ grass-addons/visualization/nviz2/wxpython/nviz/nviz.h	2008-06-25 20:47:36 UTC (rev 31845)
@@ -1,6 +1,8 @@
 #ifndef __NVIZ_H__
 #define __NVIZ_H__
 
+#include <vector>
+
 extern "C" {
 #include <grass/gis.h>
 #include <grass/gsurf.h>
@@ -49,7 +51,10 @@
     
     /* viewport */
     /* change_view.cpp */
-    void SetViewportDefault();
+    float SetViewDefault();
+    int SetView(float, float,
+		float, float, float);
+
     /* init.cpp */
     void InitView();
 

Modified: grass-addons/visualization/nviz2/wxpython/nviz.py
===================================================================
--- grass-addons/visualization/nviz2/wxpython/nviz.py	2008-06-25 18:04:38 UTC (rev 31844)
+++ grass-addons/visualization/nviz2/wxpython/nviz.py	2008-06-25 20:47:36 UTC (rev 31845)
@@ -5,6 +5,8 @@
 
 List of classes:
  - GLWindow
+ - NvizToolWindow
+ - ViewPositionWindow
 
 (C) 2008 by the GRASS Development Team
 
@@ -15,6 +17,12 @@
 @author Martin Landa <landa.martin gmail.com> (Google SoC 2008)
 """
 
+import os
+import sys
+import time
+
+from threading import Thread
+
 import wx
 try:
     from wx import glcanvas
@@ -30,6 +38,7 @@
     haveOpenGL = False
 
 import globalvar
+import gcmd
 from debug import Debug as Debug
 from mapdisp import MapWindow as MapWindow
 #try:
@@ -48,10 +57,11 @@
                  style=wx.NO_FULL_REPAINT_ON_RESIZE,
                  Map=None, tree=None, gismgr=None):
 
+        self.parent = parent # MapFrame
         self.Map = Map
         self.tree = tree
         self.gismgr = gismgr
-
+        
         glcanvas.GLCanvas.__init__(self, parent, id)
         MapWindow.__init__(self, parent, id, pos, size, style,
                            Map, tree, gismgr)
@@ -78,18 +88,43 @@
         self.nvizClass.SetDisplay(self)
 
         #
+        # set default lighting model
+        #
+        self.nvizClass.SetLightsDefault()
+
+        #
         # initialize mouse position
         #
         self.lastX = self.x = 30
         self.lastY = self.y = 30
 
+        #
+        # default values
+        #
+        self.view = { 'persp' : { 'value' : 40,
+                                  'min' : 0,
+                                  'max' : 100
+                                  },
+                      'pos' : { 'value' : (0.85, 0.85),
+                                },
+                      'height' : { 'value': -1,
+                                   'min' : -2245, # TODO: determine min/max height
+                                   'max' : 3695 
+                                   },
+                      'twist' : { 'value' : 0,
+                                  'min' : -180,
+                                  'max' : 180
+                                  },
+                      }
+
         self.size = None
         self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
         self.Bind(wx.EVT_SIZE, self.OnSize)
         self.Bind(wx.EVT_PAINT, self.OnPaint)
         self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
         self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
-        self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
+        self.Bind(wx.EVT_MOTION, self.OnMouseAction)
+        self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseAction)
 
     def OnEraseBackground(self, event):
         pass # do nothing, to avoid flashing on MSW
@@ -113,17 +148,49 @@
         if not self.init:
             self.nvizClass.InitView()
             self.LoadDataLayers()
-            self.nvizClass.SetViewportDefault()
-            self.nvizClass.SetLightsDefault()
+            self.view['height']['value'] = self.nvizClass.SetViewDefault()
+            if hasattr(self.parent, "nvizToolWin"):
+                self.parent.nvizToolWin.UpdateSettings()
             self.init = True
-        self.DrawMap()
+        self.UpdateMap()
 
-    def OnMouseMotion(self, event):
+    def OnMouseAction(self, event):
+        # change position
         if event.Dragging() and event.LeftIsDown():
             self.lastX = self.lastY = self.x = self.y
             self.x, self.y = event.GetPosition()
             self.Refresh(False)
 
+        # change perspective with mouse wheel
+        wheel = event.GetWheelRotation()
+
+        if wheel != 0:
+            current  = event.GetPositionTuple()[:]
+            Debug.msg (5, "GLWindow.OnMouseMotion(): wheel=%d" % wheel)
+            if wheel > 0:
+                value = -5 # TODO: settings
+            else:
+                value = 5
+            self.view['persp']['value'] += value
+            if self.view['persp']['value'] < 0:
+                self.view['persp']['value'] = 0
+            elif self.view['persp']['value'] > 100:
+                self.view['persp']['value'] = 100
+
+            if hasattr(self.parent, "nvizToolWin"):
+                self.parent.nvizToolWin.UpdateSettings()
+
+            self.nvizClass.SetView(self.view['pos']['value'][0], self.view['pos']['value'][1],
+                                   self.view['height']['value'],
+                                   self.view['persp']['value'],
+                                   self.view['twist']['value'])
+
+            # redraw map
+            self.OnPaint(None)
+
+            # update statusbar
+            ### self.parent.StatusbarUpdate()
+
     def OnLeftDown(self, event):
         self.CaptureMouse()
         self.x, self.y = self.lastX, self.lastY = event.GetPosition()
@@ -131,25 +198,70 @@
     def OnLeftUp(self, event):
         self.ReleaseMouse()
 
-    def DrawMap(self):
-        """Draw data layers"""
-        Debug.msg(3, "GLCanvas.Draw()")
+    def UpdateMap(self, render=True):
+        """
+        Updates the canvas anytime there is a change to the
+        underlaying images or to the geometry of the canvas.
 
-        self.nvizClass.Draw()
+        @todo render=False
 
-        #         if self.size is None:
-        #             self.size = self.GetClientSize()
+        @param render re-render map composition
+        """
+        start = time.clock()
+
+        self.resize = False
+
+        # if self.size is None:
+        #    self.size = self.GetClientSize()
         
         #         w, h = self.size
-        #         w = max(w, 1.0)
-        #         h = max(h, 1.0)
-        #         xScale = 180.0 / w
-        #         yScale = 180.0 / h
-        #         glRotatef((self.y - self.lastY) * yScale, 1.0, 0.0, 0.0);
-        #         glRotatef((self.x - self.lastX) * xScale, 0.0, 1.0, 0.0);
+        #         w = float(max(w, 1.0))
+        #         h = float(max(h, 1.0))
+        #         d = float(min(w, h))
+        #         xScale = d / w
+        #         yScale = d / h
+        # print w, h, d, xScale, yScale
+        # print self.y, self.lastY, self.x, self.lastX
+        # print (self.y - self.lastY) * yScale, (self.x - self.lastX) * xScale 
+        # print self.x * xScale
+        
+        #glRotatef((self.y - self.lastY) * yScale, 1.0, 0.0, 0.0);
+        #glRotatef((self.x - self.lastX) * xScale, 0.0, 1.0, 0.0);
 
+        if render is True:
+            self.parent.onRenderGauge.Show()
+            if self.parent.onRenderGauge.GetRange() > 0:
+                self.parent.onRenderGauge.SetValue(1)
+                self.parent.onRenderTimer.Start(100)
+            self.parent.onRenderCounter = 0
+
+        self.nvizClass.SetView(self.view['pos']['value'][0], self.view['pos']['value'][1],
+                               self.view['height']['value'],
+                               self.view['persp']['value'],
+                               self.view['twist']['value'])
+
+        self.nvizClass.Draw()
+
         self.SwapBuffers()
 
+        stop = time.clock()
+
+        #
+        # hide process bar
+        #
+        if self.parent.onRenderGauge.GetRange() > 0:
+            self.parent.onRenderTimer.Stop()
+        self.parent.onRenderGauge.Hide()
+
+        #
+        # update statusbar
+        #
+        ### self.Map.SetRegion()
+        # self.parent.StatusbarUpdate()
+
+        Debug.msg(3, "GLWindow.UpdateMap(): render=%s, -> time=%g" % \
+                      (render, (stop-start)))
+
     def EraseMap(self):
         """
         Erase the canvas
@@ -157,28 +269,236 @@
         self.nvizClass.EraseMap()
         self.SwapBuffers()
 
-    def UpdateMap(self, render=True):
-        """
-        Updates the canvas anytime there is a change to the
-        underlaying images or to the geometry of the canvas.
-
-        @todo render=False
-
-        @param render re-render map composition
-        """
-        self.nvizClass.Draw()
-        self.SwapBuffers()
-
     def LoadDataLayers(self):
         """Load raster/vector from current layer tree
 
         @todo volumes
         """
         for raster in self.Map.GetListOfLayers(l_type='raster', l_active=True):
-            print raster.name
-            self.nvizClass.LoadRaster(str(raster.name), None, None);
+            self.nvizClass.LoadRaster(str(raster.name), None, None)
 
     def Reset(self):
         """Reset (unload data)"""
         self.nvizClass.Reset()
         self.init = False
+
+    def ZoomToMap(self, event):
+        """
+        Set display extents to match selected raster
+        or vector map or volume.
+
+        @todo vector, volume
+        """
+        layer = self.GetSelectedLayer()
+
+        if layer is None:
+            return
+
+        Debug.msg (3, "GLWindow.ZoomToMap(): layer=%s, type=%s" % \
+                       (layer.name, layer.type))
+
+        self.nvizClass.SetViewportDefault()
+
+class NvizToolWindow(wx.Frame):
+    """Experimental window for Nviz tools
+
+    @todo integrated with Map display
+    """
+    def __init__(self, parent=None, id=wx.ID_ANY, title=_("Nviz tools"),
+                 pos=wx.DefaultPosition, size=wx.DefaultSize,
+                 style=wx.DEFAULT_FRAME_STYLE, settings={}):
+        
+        self.parent = parent # MapFrame
+        self.settings = settings # GLWindow.view
+
+        wx.Frame.__init__(self, parent, id, title, pos, size, style)
+
+        # dialog body
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+
+        self.win = {} # window ids
+
+        # notebook
+        self.notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
+
+        self.__createViewPage()
+
+        mainSizer.Add(item=self.notebook, proportion=1,
+                      flag=wx.EXPAND | wx.ALL, border=5)
+
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+        
+    def __createViewPage(self):
+        """Create view settings page"""
+        panel = wx.Panel(parent=self.notebook, id=wx.ID_ANY)
+        self.notebook.AddPage(page=panel,
+                              text=" %s " % _("View"))
+        
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap=3, hgap=3)
+
+        posSizer = wx.GridBagSizer(vgap=3, hgap=3)
+        posSizer.Add(item=wx.StaticText(panel, id=wx.ID_ANY, label=_("W")),
+                     pos=(1, 0), flag=wx.ALIGN_CENTER)
+        posSizer.Add(item=wx.StaticText(panel, id=wx.ID_ANY, label=_("N")),
+                     pos=(0, 1), flag=wx.ALIGN_CENTER | wx.ALIGN_BOTTOM)
+        posSizer.Add(item=ViewPositionWindow(panel, id=wx.ID_ANY, size=(175, 175),
+                                             settings=self.settings, mapwindow=self.parent.MapWindow3D),
+                     pos=(1, 1), flag=wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)
+        posSizer.Add(item=wx.StaticText(panel, id=wx.ID_ANY, label=_("S")),
+                     pos=(2, 1), flag=wx.ALIGN_CENTER | wx.ALIGN_TOP)
+        posSizer.Add(item=wx.StaticText(panel, id=wx.ID_ANY, label=_("E")),
+                     pos=(1, 2), flag=wx.ALIGN_CENTER)
+        gridSizer.Add(item=posSizer, pos=(0, 0))
+                                         
+        self.CreateControl(panel, 'persp')
+        gridSizer.Add(item=wx.StaticText(panel, id=wx.ID_ANY, label=_("Perspective:")),
+                      pos=(1, 0), flag=wx.ALIGN_CENTER)
+        gridSizer.Add(item=self.FindWindowById(self.win['persp']['slider']), pos=(2, 0))
+        gridSizer.Add(item=self.FindWindowById(self.win['persp']['spin']), pos=(3, 0),
+                      flag=wx.ALIGN_CENTER)        
+
+        self.CreateControl(panel, 'twist')
+        gridSizer.Add(item=wx.StaticText(panel, id=wx.ID_ANY, label=_("Twist:")),
+                      pos=(1, 1), flag=wx.ALIGN_CENTER)
+        gridSizer.Add(item=self.FindWindowById(self.win['twist']['slider']), pos=(2, 1))
+        gridSizer.Add(item=self.FindWindowById(self.win['twist']['spin']), pos=(3, 1),
+                      flag=wx.ALIGN_CENTER)        
+
+        self.CreateControl(panel, 'height', sliderHor=False)
+        heightSizer = wx.GridBagSizer(vgap=3, hgap=3)
+        heightSizer.Add(item=wx.StaticText(panel, id=wx.ID_ANY, label=_("Height:")),
+                      pos=(0, 0), flag=wx.ALIGN_LEFT, span=(1, 2))
+        heightSizer.Add(item=self.FindWindowById(self.win['height']['slider']),
+                        flag=wx.ALIGN_RIGHT, pos=(1, 0))
+        heightSizer.Add(item=self.FindWindowById(self.win['height']['spin']),
+                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.TOP |
+                        wx.BOTTOM | wx.RIGHT, pos=(1, 1))
+        gridSizer.Add(item=heightSizer, pos=(0, 1), flag=wx.ALIGN_RIGHT)
+
+        pageSizer.Add(item=gridSizer, proportion=1,
+                      flag=wx.EXPAND | wx.ALL,
+                      border=5)
+
+        panel.SetSizer(pageSizer)
+
+    def CreateControl(self, parent, name, sliderHor=True):
+        """Add control (Slider + SpinCtrl)"""
+        self.win[name] = {}
+        if sliderHor:
+            style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | \
+                wx.SL_BOTTOM
+            size = (200, -1)
+        else:
+            style = wx.SL_VERTICAL | wx.SL_AUTOTICKS | \
+                wx.SL_BOTTOM | wx.SL_INVERSE
+            size = (-1, 200)
+        slider = wx.Slider(parent=parent, id=wx.ID_ANY,
+                           value=self.settings[name]['value'],
+                           minValue=self.settings[name]['min'],
+                           maxValue=self.settings[name]['max'],
+                           style=style,
+                           size=size)
+
+        slider.Bind(wx.EVT_SCROLL, self.OnChangeValue)
+        self.win[name]['slider'] = slider.GetId()
+
+        spin = wx.SpinCtrl(parent=parent, id=wx.ID_ANY, size=(65, -1),
+                           initial=self.settings[name]['value'],
+                           min=self.settings[name]['min'],
+                           max=self.settings[name]['max'])
+        spin.Bind(wx.EVT_SPINCTRL, self.OnChangeValue)
+        self.win[name]['spin'] = spin.GetId()
+
+
+    def UpdateSettings(self):
+        """Update dialog settings"""
+        for control in ('height',
+                        'persp',
+                        'twist'):
+            for win in self.win[control].itervalues():
+                self.FindWindowById(win).SetValue(self.settings[control]['value'])
+
+        self.Refresh(False)
+        
+    def OnChangeValue(self, event):
+        # find control
+        winName = ''
+        for name in self.win.iterkeys():
+            for win in self.win[name].itervalues():
+                if win == event.GetId():
+                    winName = name
+                    break
+
+        if winName == '':
+            return
+
+        self.settings[winName]['value'] = event.GetInt()
+        for win in self.win[winName].itervalues():
+            self.FindWindowById(win).SetValue(self.settings[winName]['value'])
+
+        self.parent.MapWindow3D.Refresh(False)
+
+class ViewPositionWindow(wx.Window):
+    """Position control window (for NvizToolWindow)"""
+    def __init__(self, parent, id, mapwindow,
+                 pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, settings={}):
+        self.settings = settings
+        self.mapWindow = mapwindow
+
+        wx.Window.__init__(self, parent, id, pos, size)
+
+        self.SetBackgroundColour("WHITE")
+
+        self.pdc = wx.PseudoDC()
+
+        self.pdc.SetBrush(wx.Brush(colour='dark green', style=wx.SOLID))
+        self.pdc.SetPen(wx.Pen(colour='dark green', width=2, style=wx.SOLID))
+
+        self.Draw()
+
+        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
+
+    def Draw(self, pos=None):
+        w, h = self.GetClientSize()
+        w2 = w / 2
+        h2 = h / 2
+
+        if pos is None:
+            x, y = self.settings['pos']['value']
+            x = x * w2 + w2
+            y = y * h2 + h2
+        else:
+            x, y = pos
+
+        self.pdc.Clear()
+        self.pdc.BeginDrawing()
+        self.pdc.DrawLine(w2, h2, x, y)
+        self.pdc.DrawCircle(x, y, 5)
+        self.pdc.EndDrawing()
+
+    def OnPaint(self, event):
+        dc = wx.BufferedPaintDC(self)
+        dc.SetBackground(wx.Brush("White"))
+        dc.Clear()
+
+        self.PrepareDC(dc)
+        self.pdc.DrawToDC(dc)
+
+    def OnMouse(self, event):
+        if event.LeftIsDown():
+            x, y = event.GetPosition()
+            self.Draw(pos=(x, y))
+            self.Refresh(False)
+            w, h = self.GetClientSize()
+            w2 = w / 2.
+            h2 = h / 2.
+            x = x / w2 - 1
+            y = y / h2 - 1
+            self.settings['pos']['value'] = (x, y)
+
+            self.mapWindow.Refresh(False)



More information about the grass-commit mailing list