root/OpenSceneGraph/trunk/src/osgGA/TerrainManipulator.cpp @ 11709

Revision 11709, 9.4 kB (checked in by robert, 4 years ago)

Changed setTransformation(eye, center, up) paramter ordering to match gluLookAt conventions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osgGA/TerrainManipulator>
15#include <osgUtil/LineSegmentIntersector>
16#include <osg/io_utils>
17
18using namespace osg;
19using namespace osgGA;
20
21
22
23/// Constructor.
24TerrainManipulator::TerrainManipulator( int flags )
25    : inherited( flags )
26{
27}
28
29
30/// Constructor.
31TerrainManipulator::TerrainManipulator( const TerrainManipulator& tm, const CopyOp& copyOp )
32    : inherited( tm, copyOp ),
33      _previousUp( tm._previousUp )
34{
35}
36
37
38/** Sets the manipulator rotation mode. RotationMode is now deprecated by
39    osgGA::StandardManipulator::setVerticalAxisFixed() functionality,
40    that is used across StandardManipulator derived classes.*/
41void TerrainManipulator::setRotationMode( TerrainManipulator::RotationMode mode )
42{
43    setVerticalAxisFixed( mode == ELEVATION_AZIM );
44}
45
46
47/** Returns the manipulator rotation mode.*/
48TerrainManipulator::RotationMode TerrainManipulator::getRotationMode() const
49{
50    return getVerticalAxisFixed() ? ELEVATION_AZIM : ELEVATION_AZIM_ROLL;
51}
52
53
54void TerrainManipulator::setNode( Node* node )
55{
56    inherited::setNode( node );
57
58    // update model size
59    if( _flags & UPDATE_MODEL_SIZE )
60    {
61        if( _node.valid() )
62        {
63            setMinimumDistance( clampBetween( _modelSize * 0.001, 0.00001, 1.0 ) );
64            OSG_INFO << "TerrainManipulator: setting _minimumDistance to "
65                     << _minimumDistance << std::endl;
66        }
67    }
68}
69
70
71void TerrainManipulator::setByMatrix(const Matrixd& matrix)
72{
73
74    Vec3d lookVector(- matrix(2,0),-matrix(2,1),-matrix(2,2));
75    Vec3d eye(matrix(3,0),matrix(3,1),matrix(3,2));
76
77    OSG_INFO<<"eye point "<<eye<<std::endl;
78    OSG_INFO<<"lookVector "<<lookVector<<std::endl;
79
80    if (!_node)
81    {
82        _center = eye+ lookVector;
83        _distance = lookVector.length();
84        _rotation = matrix.getRotate();
85        return;
86    }
87
88
89    // need to reintersect with the terrain
90    const BoundingSphere& bs = _node->getBound();
91    float distance = (eye-bs.center()).length() + _node->getBound().radius();
92    Vec3d start_segment = eye;
93    Vec3d end_segment = eye + lookVector*distance;
94
95    Vec3d ip;
96    bool hitFound = false;
97    if (intersect(start_segment, end_segment, ip))
98    {
99        OSG_INFO << "Hit terrain ok A"<< std::endl;
100        _center = ip;
101
102        _distance = (eye-ip).length();
103
104        Matrixd rotation_matrix = Matrixd::translate(0.0,0.0,-_distance)*
105                                  matrix*
106                                  Matrixd::translate(-_center);
107
108        _rotation = rotation_matrix.getRotate();
109
110        hitFound = true;
111    }
112
113    if (!hitFound)
114    {
115        CoordinateFrame eyePointCoordFrame = getCoordinateFrame( eye );
116
117        if (intersect(eye+getUpVector(eyePointCoordFrame)*distance,
118                      eye-getUpVector(eyePointCoordFrame)*distance,
119                      ip))
120        {
121            _center = ip;
122
123            _distance = (eye-ip).length();
124
125            _rotation.set(0,0,0,1);
126
127            hitFound = true;
128        }
129    }
130
131
132    CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
133    _previousUp = getUpVector(coordinateFrame);
134
135    clampOrientation();
136}
137
138
139void TerrainManipulator::setTransformation( const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up )
140{
141    if (!_node) return;
142
143    // compute rotation matrix
144    Vec3d lv(center-eye);
145    _distance = lv.length();
146    _center = center;
147
148    OSG_INFO << "In compute"<< std::endl;
149
150    if (_node.valid())
151    {
152        bool hitFound = false;
153
154        double distance = lv.length();
155        double maxDistance = distance+2*(eye-_node->getBound().center()).length();
156        Vec3d farPosition = eye+lv*(maxDistance/distance);
157        Vec3d endPoint = center;
158        for(int i=0;
159            !hitFound && i<2;
160            ++i, endPoint = farPosition)
161        {
162            // compute the intersection with the scene.
163
164            Vec3d ip;
165            if (intersect(eye, endPoint, ip))
166            {
167                _center = ip;
168                _distance = (ip-eye).length();
169
170                hitFound = true;
171            }
172        }
173    }
174
175    // note LookAt = inv(CF)*inv(RM)*inv(T) which is equivalent to:
176    // inv(R) = CF*LookAt.
177
178    Matrixd rotation_matrix = Matrixd::lookAt(eye,center,up);
179
180    _rotation = rotation_matrix.getRotate().inverse();
181
182    CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
183    _previousUp = getUpVector(coordinateFrame);
184
185    clampOrientation();
186}
187
188
189bool TerrainManipulator::intersect( const Vec3d& start, const Vec3d& end, Vec3d& intersection ) const
190{
191    ref_ptr<osgUtil::LineSegmentIntersector> lsi = new osgUtil::LineSegmentIntersector(start,end);
192
193    osgUtil::IntersectionVisitor iv(lsi.get());
194    iv.setTraversalMask(_intersectTraversalMask);
195
196    _node->accept(iv);
197
198    if (lsi->containsIntersections())
199    {
200        intersection = lsi->getIntersections().begin()->getWorldIntersectPoint();
201        return true;
202    }
203    return false;
204}
205
206
207bool TerrainManipulator::performMovementMiddleMouseButton( const double eventTimeDelta, const double dx, const double dy )
208{
209    // pan model.
210    double scale = -0.3f * _distance * getThrowScale( eventTimeDelta );
211
212    Matrixd rotation_matrix;
213    rotation_matrix.makeRotate(_rotation);
214
215
216    // compute look vector.
217    Vec3d lookVector = -getUpVector(rotation_matrix);
218    Vec3d sideVector = getSideVector(rotation_matrix);
219    Vec3d upVector = getFrontVector(rotation_matrix);
220
221    // CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
222    // Vec3d localUp = getUpVector(coordinateFrame);
223    Vec3d localUp = _previousUp;
224
225    Vec3d forwardVector =localUp^sideVector;
226    sideVector = forwardVector^localUp;
227
228    forwardVector.normalize();
229    sideVector.normalize();
230
231    Vec3d dv = forwardVector * (dy*scale) + sideVector * (dx*scale);
232
233    _center += dv;
234
235    // need to recompute the intersection point along the look vector.
236
237    bool hitFound = false;
238
239    if (_node.valid())
240    {
241        // now reorientate the coordinate frame to the frame coords.
242        CoordinateFrame coordinateFrame =  getCoordinateFrame(_center);
243
244        // need to reintersect with the terrain
245        double distance = _node->getBound().radius()*0.25f;
246
247        Vec3d ip1;
248        Vec3d ip2;
249        bool hit_ip1 = intersect(_center, _center + getUpVector(coordinateFrame) * distance, ip1);
250        bool hit_ip2 = intersect(_center, _center - getUpVector(coordinateFrame) * distance, ip2);
251        if (hit_ip1)
252        {
253            if (hit_ip2)
254            {
255                _center = (_center-ip1).length2() < (_center-ip2).length2() ?
256                            ip1 :
257                            ip2;
258
259                hitFound = true;
260            }
261            else
262            {
263                _center = ip1;
264                hitFound = true;
265            }
266        }
267        else if (hit_ip2)
268        {
269            _center = ip2;
270            hitFound = true;
271        }
272
273        if (!hitFound)
274        {
275            // ??
276            OSG_INFO<<"TerrainManipulator unable to intersect with terrain."<<std::endl;
277        }
278
279        coordinateFrame = getCoordinateFrame(_center);
280        Vec3d new_localUp = getUpVector(coordinateFrame);
281
282
283        Quat pan_rotation;
284        pan_rotation.makeRotate(localUp,new_localUp);
285
286        if (!pan_rotation.zeroRotation())
287        {
288            _rotation = _rotation * pan_rotation;
289            _previousUp = new_localUp;
290            //OSG_NOTICE<<"Rotating from "<<localUp<<" to "<<new_localUp<<"  angle = "<<acos(localUp*new_localUp/(localUp.length()*new_localUp.length()))<<std::endl;
291
292            //clampOrientation();
293        }
294        else
295        {
296            OSG_INFO<<"New up orientation nearly inline - no need to rotate"<<std::endl;
297        }
298    }
299
300    return true;
301}
302
303
304bool TerrainManipulator::performMovementRightMouseButton( const double eventTimeDelta, const double dx, const double dy )
305{
306    // zoom model
307    zoomModel( dy * getThrowScale( eventTimeDelta ), false );
308    return true;
309}
310
311
312void TerrainManipulator::clampOrientation()
313{
314    if (!getVerticalAxisFixed())
315    {
316        Matrixd rotation_matrix;
317        rotation_matrix.makeRotate(_rotation);
318
319        Vec3d lookVector = -getUpVector(rotation_matrix);
320        Vec3d upVector = getFrontVector(rotation_matrix);
321
322        CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
323        Vec3d localUp = getUpVector(coordinateFrame);
324        //Vec3d localUp = _previousUp;
325
326        Vec3d sideVector = lookVector ^ localUp;
327
328        if (sideVector.length()<0.1)
329        {
330            OSG_INFO<<"Side vector short "<<sideVector.length()<<std::endl;
331
332            sideVector = upVector^localUp;
333            sideVector.normalize();
334        }
335
336        Vec3d newUpVector = sideVector^lookVector;
337        newUpVector.normalize();
338
339        Quat rotate_roll;
340        rotate_roll.makeRotate(upVector,newUpVector);
341
342        if (!rotate_roll.zeroRotation())
343        {
344            _rotation = _rotation * rotate_roll;
345        }
346    }
347}
Note: See TracBrowser for help on using the browser.