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