[GRASS-SVN] r48971 - in grass/trunk: gui/wxpython/gui_modules gui/wxpython/icons include lib/nviz

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Oct 27 15:23:21 EDT 2011


Author: annakrat
Date: 2011-10-27 12:23:21 -0700 (Thu, 27 Oct 2011)
New Revision: 48971

Modified:
   grass/trunk/gui/wxpython/gui_modules/mapdisp.py
   grass/trunk/gui/wxpython/gui_modules/nviz_mapdisp.py
   grass/trunk/gui/wxpython/gui_modules/nviz_preferences.py
   grass/trunk/gui/wxpython/gui_modules/nviz_tools.py
   grass/trunk/gui/wxpython/gui_modules/preferences.py
   grass/trunk/gui/wxpython/gui_modules/wxnviz.py
   grass/trunk/gui/wxpython/icons/icon.py
   grass/trunk/include/nviz.h
   grass/trunk/lib/nviz/change_view.c
Log:
wxNviz: fly-through mode added

Modified: grass/trunk/gui/wxpython/gui_modules/mapdisp.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/mapdisp.py	2011-10-27 16:47:34 UTC (rev 48970)
+++ grass/trunk/gui/wxpython/gui_modules/mapdisp.py	2011-10-27 19:23:21 UTC (rev 48971)
@@ -599,7 +599,9 @@
         self.toolbars['map'].Enable2D(False)
         # add rotate tool to map toolbar
         self.toolbars['map'].InsertTool((('rotate', Icons['nviz']['rotate'],
-                                          self.OnRotate, wx.ITEM_CHECK,7),)) # 7 is position
+                                          self.OnRotate, wx.ITEM_CHECK, 7),)) # 7 is position
+        self.toolbars['map'].InsertTool((('flyThrough', Icons['nviz']['flyThrough'],
+                                          self.OnFlyThrough, wx.ITEM_CHECK, 8),)) 
         self.toolbars['map'].ChangeToolsDesc(mode2d = False)
         # update status bar
         
@@ -662,6 +664,7 @@
     def RemoveNviz(self):
         """!Restore 2D view"""
         self.toolbars['map'].RemoveTool(self.toolbars['map'].rotate)
+        self.toolbars['map'].RemoveTool(self.toolbars['map'].flyThrough)
         # update status bar
         self.statusbarManager.ShowStatusbarChoiceItemsByClass(self.statusbarItemsHiddenInNviz)
         self.statusbarManager.SetMode(UserSettings.Get(group = 'display',
@@ -670,7 +673,7 @@
         self.SetStatusText(_("Please wait, unloading data..."), 0)
         self._layerManager.goutput.WriteCmdLog(_("Switching back to 2D view mode..."),
                                                switchPage = False)
-        self.MapWindow3D.UnloadDataLayers(force = True)
+        self.MapWindow3D.OnClose(event = None)
         # switch from MapWindowGL to MapWindow
         self._mgr.GetPane('2d').Show()
         self._mgr.GetPane('3d').Hide()
@@ -827,6 +830,19 @@
         # change the cursor
         self.MapWindow.SetCursor(self.cursors["hand"])
 
+    def OnFlyThrough(self, event):
+        """!Fly-through mode
+        """
+        if self.GetMapToolbar():
+            self.toolbars['map'].OnTool(event)
+            self.toolbars['map'].action['desc'] = ''
+        
+        self.MapWindow.mouse['use'] = "fly"
+        
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["hand"])
+        self.MapWindow.SetFocus()
+        
     def OnZoomRegion(self, event):
         """!Zoom to region
         """

Modified: grass/trunk/gui/wxpython/gui_modules/nviz_mapdisp.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/nviz_mapdisp.py	2011-10-27 16:47:34 UTC (rev 48970)
+++ grass/trunk/gui/wxpython/gui_modules/nviz_mapdisp.py	2011-10-27 19:23:21 UTC (rev 48971)
@@ -154,7 +154,11 @@
         self.decoration = self.nvizDefault.SetDecorDefaultProp(type = 'arrow')
         self.decoration['scalebar'] = []
         self.decoration['arrow']['size'] = self._getDecorationSize()
+        self.fly = self.InitFly()
         
+        # timer for flythrough
+        self.timerFly = wx.Timer(self, id = wx.NewId())
+        
         self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
         self.Bind(wx.EVT_SIZE,             self.OnSize)
         self.Bind(wx.EVT_PAINT,            self.OnPaint)
@@ -165,14 +169,107 @@
         self.Bind(EVT_UPDATE_LIGHT,  self.UpdateLight)
         self.Bind(EVT_UPDATE_CPLANE, self.UpdateCPlane)
         
+        self.Bind(wx.EVT_TIMER, self.OnTimerFly, self.timerFly)
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
+        
         self.Bind(wx.EVT_CLOSE, self.OnClose)
         
         # cplanes cannot be initialized now
         wx.CallAfter(self.InitCPlanes)
 
+    def InitFly(self):
+        """!Initialize fly through dictionary"""
+        fly = {'interval' : 10,             # interval for timerFly
+               'value': [0, 0, 0],          # calculated values for navigation
+               'mode' : 0,                  # fly through mode (0, 1)
+               'exag' : {                   # sensitivity
+                    'move' : UserSettings.Get(group = 'nviz', key = 'fly', subkey = ['exag', 'move']),
+                    'turn' : UserSettings.Get(group = 'nviz', key = 'fly', subkey = ['exag', 'turn'])},
+               'exagMultiplier' : 3,        # speed up by Shift
+               'mouseControl' : None,       # if mouse or keys are used
+               'pos' : {'x' : 0, 'y' : 0},  # virtual mouse position when using arrows
+               'arrowStep' : 50,            # step in pixels (when using arrows)
+            }
+            
+        return fly
+        
+    def OnTimerFly(self, event):
+        """!Fly event was emitted, move the scene"""
+        if self.mouse['use'] != 'fly':
+            return
+        
+        if self.fly['mouseControl']:
+            mx, my = self.ComputeMxMy(*self.mouse['tmp'])
+        else:
+            mx, my = self.ComputeMxMy(self.fly['pos']['x'], self.fly['pos']['y'])
+            
+        self.ComputeFlyValues(mx = mx, my = my)
+        self._display.FlyThrough(flyInfo = self.fly['value'], mode = self.fly['mode'],
+                                 exagInfo = self.fly['exag'])
+        self.render['quick'] = True
+        self.Refresh(False)
+        
+    def ComputeMxMy(self, x, y):
+        """!Compute values for flythrough navigation 
+        (ComputeFlyValues should follow). 
+        
+        Based on visualization/nviz/src/togl_flythrough.c.
+        @param x,y screen coordinates
+        """
+        sx, sy = self.GetClientSizeTuple()
+        dx = dy = 0.01
+        
+        mx = 2 * (float(x) / sx) - 1
+        my = 2 * (float(y) / sy) - 1
+    
+        if mx < - dx:
+            mx += dx
+        elif mx > dx:
+            mx -= dx
+        else:
+            mx = 0.0 # ?
+        if my < - dy:
+            my += dy
+        elif my > dy:
+            my -= dy
+        else:
+            my = 0.0
+    
+        mx = mx / (1.0 - dx)
+        my = my / (1.0 - dy)
+    
+        # Quadratic seems smoother 
+        mx *= abs(mx)
+        my *= abs(my)
+        
+        return mx, my
+        
+    def ComputeFlyValues(self, mx, my):
+        """!Compute parameters for fly-through navigation
+        
+        @params mx,my results from ComputeMxMy method
+        """
+        self.fly['value'] = [0, 0, 0]
+        
+        if self.fly['mode'] == 0:
+            self.fly['value'][0] = - my * 500.0 * self.fly['interval'] / 1000. # forward */
+            self.fly['value'][1] = mx * 0.1 *self.fly['interval'] / 1000.  # heading */
+        else:
+            self.fly['value'][0] = mx * 100.0 * self.fly['interval'] /1000.
+            self.fly['value'][2] = - my * 100.0 * self.fly['interval'] /1000.
+    
+    
     def __del__(self):
+        """!Stop timers if running, unload data"""
+        self.StopTimer(self.timerFly)
         self.UnloadDataLayers(force = True)
-        
+    
+    def StopTimer(self, timer):
+        """!Stop timer if running"""
+        if timer.IsRunning():
+            timer.Stop()
+            
     def _bindMouseEvents(self):
         self.Bind(wx.EVT_MOUSE_EVENTS,     self.OnMouseAction)
         self.Bind(wx.EVT_MOTION,           self.OnMotion)
@@ -185,6 +282,7 @@
             self.cplanes.append(cplane)
             
     def OnClose(self, event):
+        self.StopTimer(self.timerFly)
         # cleanup when window actually closes (on quit) and not just is hidden
         self.UnloadDataLayers(force = True)
         
@@ -201,6 +299,13 @@
             self._display.ResizeWindow(size.width,
                                        size.height)
         self.size = size
+        
+        # reposition checkbox in statusbar
+        self.parent.StatusbarReposition()
+        
+        # update statusbar
+        self.parent.StatusbarUpdate()
+        
         event.Skip()
        
     def OnPaint(self, event):
@@ -386,8 +491,70 @@
             if texture.HitTest(mouseX, mouseY, radius):
                 return texture.id
         return -1
-                
-                    
+        
+    def OnKeyDown(self, event):
+        """!Key was pressed.
+        
+        Used for fly-through mode.
+        """
+        if not self.mouse['use'] == 'fly':
+            return
+            
+        key = event.GetKeyCode()
+        if key == wx.WXK_CONTROL: # Mac ?
+            self.fly['mode'] = 1
+            
+        elif key == wx.WXK_SHIFT: 
+            self.fly['exag']['move'] *= self.fly['exagMultiplier']
+            self.fly['exag']['turn'] *= self.fly['exagMultiplier']
+            
+        elif key == wx.WXK_ESCAPE and self.timerFly.IsRunning() and not self.fly['mouseControl']:
+            self.StopTimer(self.timerFly)
+            self.fly['mouseControl'] = None
+            self.render['quick'] = False
+            self.Refresh(False)
+            
+        elif key in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT):
+            if not self.timerFly.IsRunning():
+                sx, sy = self.GetClientSizeTuple()
+                self.fly['pos']['x'] = sx / 2
+                self.fly['pos']['y'] = sy / 2
+                self.fly['mouseControl'] = False # controlled by keyboard
+                self.timerFly.Start(self.fly['interval'])
+
+            self.ProcessFlyByArrows(keyCode = key)
+        
+        event.Skip()
+        
+    def ProcessFlyByArrows(self, keyCode):
+        """!Process arrow key during fly-through"""
+        step = self.fly['arrowStep']
+        if keyCode == wx.WXK_UP:
+            self.fly['pos']['y'] -= step
+        elif keyCode == wx.WXK_DOWN:
+            self.fly['pos']['y'] += step
+        elif keyCode == wx.WXK_LEFT:
+            self.fly['pos']['x'] -= step
+        elif keyCode == wx.WXK_RIGHT:
+            self.fly['pos']['x'] += step
+            
+    def OnKeyUp(self, event):
+        """!Key was released.
+        
+        Used for fly-through mode.
+        """
+        if not self.mouse['use'] == 'fly':
+            return
+            
+        key = event.GetKeyCode()
+        if key == wx.WXK_CONTROL: # Mac ?
+            self.fly['mode'] = 0
+        elif key == wx.WXK_SHIFT: 
+            self.fly['exag']['move'] = math.floor(self.fly['exag']['move'] / self.fly['exagMultiplier'])
+            self.fly['exag']['turn'] = math.floor(self.fly['exag']['turn'] / self.fly['exagMultiplier'])
+        
+        event.Skip()
+        
     def OnMouseAction(self, event):
         """!Handle mouse events"""
         # zoom with mouse wheel
@@ -453,6 +620,11 @@
             self.dragid = self.FindObjects(self.mouse['tmp'][0], self.mouse['tmp'][1],
                                           self.hitradius)   
                 
+        if self.mouse['use'] == 'fly':
+            if not self.timerFly.IsRunning():
+                self.timerFly.Start(self.fly['interval'])
+                self.fly['mouseControl'] = True
+            
         event.Skip()    
         
     def OnDragging(self, event):
@@ -463,7 +635,7 @@
             
         if self.mouse['use'] == 'rotate':    
             dx, dy = event.GetX() - self.mouse['tmp'][0], event.GetY() - self.mouse['tmp'][1]
-            self.mouse['tmp'] = event.GetPositionTuple()
+            
             angle, x, y, z = self._display.GetRotationParameters(dx, dy)
             self._display.Rotate(angle, x, y, z)
             
@@ -472,6 +644,8 @@
             
         if self.mouse['use'] == 'pan':
             self.FocusPanning(event)
+            
+        self.mouse['tmp'] = event.GetPositionTuple()
                 
         event.Skip()
             
@@ -568,11 +742,19 @@
             self.saveHistory = True
             self.render['quick'] = False
             self.Refresh(False)
+            
         elif self.mouse['use'] == 'pan':
             self.saveHistory = True
             self.render['quick'] = False
             self.Refresh(False)
             
+        elif self.mouse['use'] == 'fly':
+            if self.fly['mouseControl']:
+                self.StopTimer(self.timerFly)
+                self.fly['mouseControl'] = None
+                self.render['quick'] = False
+                self.Refresh(False)
+            
         elif self.mouse['use'] == 'zoom':
             self.DoZoom(zoomtype = self.zoomtype, pos = self.mouse['end'])
         event.Skip()
@@ -1481,22 +1663,6 @@
             
         if remove and item in self.layers:
             self.layers.remove(item)
-        
-    def OnZoomToMap(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.OnZoomToMap(): layer = %s, type = %s" % \
-                       (layer.name, layer.type))
-        
-        self._display.SetViewportDefault()
 
     def ResetView(self):
         """!Reset to default view"""
@@ -2251,8 +2417,10 @@
         """!Get display instance"""
         return self._display
         
-    def ZoomToMap(self):
+    def ZoomToMap(self, layers):
         """!Reset view
+        
+        @param layers so far unused
         """
         self.lmgr.nviz.OnResetView(None)
         

Modified: grass/trunk/gui/wxpython/gui_modules/nviz_preferences.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/nviz_preferences.py	2011-10-27 16:47:34 UTC (rev 48970)
+++ grass/trunk/gui/wxpython/gui_modules/nviz_preferences.py	2011-10-27 19:23:21 UTC (rev 48971)
@@ -36,6 +36,7 @@
         
         # create notebook pages
         self._createViewPage(self.notebook)
+        self._createFlyPage(self.notebook)
         self._createLightPage(self.notebook)
         self._createSurfacePage(self.notebook)
         self._createVectorPage(self.notebook)
@@ -192,7 +193,55 @@
         panel.SetSizer(pageSizer)
         
         return panel
-    
+        
+    def _createFlyPage(self, notebook):
+        """!Create notebook page for view settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        
+        notebook.AddPage(page = panel,
+                         text = " %s " % _("Fly-through"))
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        # fly throuhg mode
+        box = wx.StaticBox(parent = panel, id = wx.ID_ANY,
+                           label = " %s " % (_("Fly-through mode")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        # move exag
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Move exag:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        moveExag = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 20, 
+                                  initial = UserSettings.Get(group = 'nviz', key = 'fly',
+                                                             subkey = ['exag', 'move']),
+                                  size = (65, -1))
+        self.winId['nviz:fly:exag:move'] = moveExag.GetId()
+        gridSizer.Add(item = moveExag, pos = (0, 1))
+        
+        # turn exag
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Turn exag:")),
+                      pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        turnExag = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 20, 
+                                  initial = UserSettings.Get(group = 'nviz', key = 'fly',
+                                                             subkey = ['exag', 'turn']),
+                                  size = (65, -1))
+        self.winId['nviz:fly:exag:turn'] = turnExag.GetId()
+        gridSizer.Add(item = turnExag, pos = (1, 1))
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL,
+                      border = 5)
+        
+        panel.SetSizer(pageSizer)
+        
+        return panel
+        
     def _createLightPage(self, notebook):
         """!Create notebook page for light settings"""
         panel = wx.Panel(parent = notebook, id = wx.ID_ANY)

Modified: grass/trunk/gui/wxpython/gui_modules/nviz_tools.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/nviz_tools.py	2011-10-27 16:47:34 UTC (rev 48970)
+++ grass/trunk/gui/wxpython/gui_modules/nviz_tools.py	2011-10-27 19:23:21 UTC (rev 48971)
@@ -239,12 +239,15 @@
             self.mapWindow.light = kwargs['light']  
             self.FindWindowById(self.win['light']['position']).data = kwargs['light']  
             self.FindWindowById(self.win['light']['position']).PostDraw()
+        if 'fly' in kwargs:
+            self.mapWindow.fly['exag'] = kwargs['fly']['exag']
     
     def LoadSettings(self):
         """!Load Nviz settings and apply to current session"""
         view = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'view')) # copy
         light = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'light')) # copy
-        self.UpdateState(view = view, light = light)
+        fly = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'fly')) # copy
+        self.UpdateState(view = view, light = light, fly = fly)
         self.PostViewEvent(zExag = True)
         self.PostLightEvent()
         self.UpdatePage('view')

Modified: grass/trunk/gui/wxpython/gui_modules/preferences.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/preferences.py	2011-10-27 16:47:34 UTC (rev 48970)
+++ grass/trunk/gui/wxpython/gui_modules/preferences.py	2011-10-27 19:23:21 UTC (rev 48971)
@@ -543,6 +543,12 @@
                         'color' : (255, 255, 255, 255), # white
                         },
                     },
+                'fly' : {
+                    'exag' : {
+                        'move' : 1,
+                        'turn' : 1,
+                        }
+                    },
                 'surface' : {
                     'shine': {
                         'map' : False,

Modified: grass/trunk/gui/wxpython/gui_modules/wxnviz.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/wxnviz.py	2011-10-27 16:47:34 UTC (rev 48970)
+++ grass/trunk/gui/wxpython/gui_modules/wxnviz.py	2011-10-27 19:23:21 UTC (rev 48971)
@@ -1860,7 +1860,21 @@
     def Start2D(self):
         Nviz_set_2D(self.width, self.height)
         
+    def FlyThrough(self, flyInfo, mode, exagInfo):
+        """!Fly through the scene
         
+        @param flyInfo fly parameters
+        @param mode 0 or 1 for different fly behaviour
+        @param exagInfo parameters changing fly speed
+        """
+        fly = (c_float * 3)()
+        for i, item in enumerate(flyInfo):
+            fly[i] = item
+        exag = (c_int * 2)()
+        exag[0] = int(exagInfo['move'])
+        exag[1] = int(exagInfo['turn'])
+        Nviz_flythrough(self.data, fly, exag, mode)
+        
 class Texture(object):
     """!Class representing OpenGL texture"""
     def __init__(self, filepath, overlayId, coords):

Modified: grass/trunk/gui/wxpython/icons/icon.py
===================================================================
--- grass/trunk/gui/wxpython/icons/icon.py	2011-10-27 16:47:34 UTC (rev 48970)
+++ grass/trunk/gui/wxpython/icons/icon.py	2011-10-27 19:23:21 UTC (rev 48971)
@@ -342,6 +342,10 @@
         'rotate':   MetaIcon(img = iconSet.get('3d-rotate', wx.ART_ERROR),
                              label = _('Rotate 3D scene'),
                              desc = _('Drag with mouse to rotate 3D scene')), 
+        'flyThrough':   MetaIcon(img = iconSet.get('', wx.ART_MISSING_IMAGE),
+                             label = _('Fly-through mode'),
+                             desc = _('Drag with mouse, hold Ctrl down for different mode'
+                                      ' or Shift to accelerate')),
         'zoomIn':   MetaIcon(img = iconSet.get('zoom-in', wx.ART_ERROR),
                             label = _('Zoom in'),
                             desc = _('Click mouse to zoom')),

Modified: grass/trunk/include/nviz.h
===================================================================
--- grass/trunk/include/nviz.h	2011-10-27 16:47:34 UTC (rev 48970)
+++ grass/trunk/include/nviz.h	2011-10-27 19:23:21 UTC (rev 48971)
@@ -157,6 +157,7 @@
 void Nviz_set_rotation(double, double, double, double);
 void Nviz_unset_rotation(void);
 void Nviz_init_rotation(void);
+void Nviz_flythrough(nv_data *, float *, int *, int);
 
 /* cplanes_obj.c */
 int Nviz_new_cplane(nv_data *, int);

Modified: grass/trunk/lib/nviz/change_view.c
===================================================================
--- grass/trunk/lib/nviz/change_view.c	2011-10-27 16:47:34 UTC (rev 48970)
+++ grass/trunk/lib/nviz/change_view.c	2011-10-27 19:23:21 UTC (rev 48971)
@@ -12,6 +12,8 @@
    \author Updated/modified by Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
  */
 
+#include <math.h>
+
 #include <grass/glocale.h>
 #include <grass/nviz.h>
 
@@ -275,3 +277,73 @@
 {
     GS_init_rotation();
 }
+
+/*!
+  \brief Fly through the scene
+
+  Computes parameters needed for moving scene.
+  Changes viewpoint and viewdir.
+  Based on visualization/nviz/src/togl_flythrough.c and simplified.
+
+  \param fly_info values computed from mouse movement
+  \param scale rate of movement
+  \param lateral type of movement
+  
+*/
+void Nviz_flythrough(nv_data *data, float *fly_info, int *scale, int lateral)
+{
+    float dir[3], from[4], cur_from[4], cur_dir[4], cur[3];
+    float speed, h, p, sh, ch, sp, cp;
+    float diff_x, diff_y, diff_z;
+    float quasi_zero;
+
+    quasi_zero = 0.0001;
+
+    GS_get_from(cur_from);
+    GS_get_viewdir(cur_dir);
+
+    p = asin(cur_dir[Z]);
+    h = atan2(- cur_dir[X], - cur_dir[Y]);
+
+    speed = scale[0] * fly_info[0];
+
+    h += scale[1] * fly_info[1]; /* change heading */
+    //if (!lateral)   /* in case of "lateral" doesn't change pitch */
+        //p -= scale * fly_info[2];
+
+    h = fmod(h + M_PI, 2 * M_PI) - M_PI;
+
+    sh = sin(h);
+    ch = cos(h);
+    sp = sin(p);
+    cp = cos(p);
+
+    dir[X] = -sh * cp;
+    dir[Y] = -ch * cp;
+    dir[Z] = sp;
+
+    if (lateral) {
+        from[X] = cur_from[X] + speed * dir[Y];
+        from[Y] = cur_from[Y] - speed * dir[X];
+        from[Z] = cur_from[Z] + scale[0] * fly_info[2];
+    }
+    else {
+        from[X] = cur_from[X] + speed * dir[X];
+        from[Y] = cur_from[Y] + speed * dir[Y];
+        /* not sure how this should behave (change Z coord or not ?)*/
+        from[Z] = cur_from[Z]; /* + speed * dir[Z]*/
+    }
+
+    diff_x = fabs(cur_dir[X] - dir[X]);
+    diff_y = fabs(cur_dir[Y] - dir[Y]);
+    diff_z = fabs(cur_dir[Z] - dir[Z]);
+
+    if (    /* something has changed */
+        (diff_x > quasi_zero) || (diff_y > quasi_zero) ||
+        (diff_z > quasi_zero) || (cur_from[X] != from[X]) ||
+        (cur_from[Y] != from[Y]) || (cur_from[Z] != from[Z])
+    ) {
+    GS_moveto(from);
+    GS_set_viewdir(dir);	/* calls gsd_set_view */
+    }
+}



More information about the grass-commit mailing list