[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