root/OpenSceneGraph/trunk/src/osg/AutoTransform.cpp @ 13041

Revision 13041, 14.2 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • 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#include <osg/AutoTransform>
14#include <osg/CullStack>
15#include <osg/Notify>
16#include <osg/io_utils>
17
18using namespace osg;
19
20AutoTransform::AutoTransform():
21    _autoUpdateEyeMovementTolerance(0.0),
22    _autoRotateMode(NO_ROTATION),
23    _autoScaleToScreen(false),
24    _scale(1.0,1.0,1.0),
25    _firstTimeToInitEyePoint(true),
26    _previousWidth(0),
27    _previousHeight(0),
28    _minimumScale(0.0),
29    _maximumScale(DBL_MAX),
30    _autoScaleTransitionWidthRatio(0.25),
31    _matrixDirty(true),
32    _axis(0.0f,0.0f,1.0f),
33    _normal(0.0f,-1.0f,0.0f),
34    _cachedMode(NO_ROTATION),
35    _side(1.0f,0.0,0.0f)
36{
37//    setNumChildrenRequiringUpdateTraversal(1);
38}
39
40AutoTransform::AutoTransform(const AutoTransform& pat,const CopyOp& copyop):
41    Transform(pat,copyop),
42    _position(pat._position),
43    _pivotPoint(pat._pivotPoint),
44    _autoUpdateEyeMovementTolerance(pat._autoUpdateEyeMovementTolerance),
45    _autoRotateMode(pat._autoRotateMode),
46    _autoScaleToScreen(pat._autoScaleToScreen),
47    _rotation(pat._rotation),
48    _scale(pat._scale),
49    _firstTimeToInitEyePoint(true),
50    _previousWidth(0),
51    _previousHeight(0),
52    _minimumScale(pat._minimumScale),
53    _maximumScale(pat._maximumScale),
54    _autoScaleTransitionWidthRatio(pat._autoScaleTransitionWidthRatio),
55    _matrixDirty(true),
56    _axis(pat._axis),
57    _normal(pat._normal),
58    _cachedMode(pat._cachedMode),
59    _side(pat._side)
60{
61//    setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1);
62}
63
64void AutoTransform::setAutoRotateMode(AutoRotateMode mode)
65{
66    _autoRotateMode = mode;
67    _firstTimeToInitEyePoint = true;
68    _cachedMode = CACHE_DIRTY;
69    updateCache();
70}
71
72void AutoTransform::setAxis(const Vec3& axis)
73{
74    _axis = axis;
75    _axis.normalize();
76    updateCache();
77}
78
79void AutoTransform::setNormal(const Vec3& normal)
80{
81    _normal = normal;
82    _normal.normalize();
83    updateCache();
84}
85
86void AutoTransform::updateCache()
87{
88    if (_autoRotateMode==ROTATE_TO_AXIS)
89    {
90        if      (_axis==Vec3(1.0f,0.0,0.0f) && _normal==Vec3(0.0f,-1.0,0.0f)) _cachedMode = AXIAL_ROT_X_AXIS;
91        else if (_axis==Vec3(0.0f,1.0,0.0f) && _normal==Vec3(1.0f, 0.0,0.0f)) _cachedMode = AXIAL_ROT_Y_AXIS;
92        else if (_axis==Vec3(0.0f,0.0,1.0f) && _normal==Vec3(0.0f,-1.0,0.0f)) _cachedMode = AXIAL_ROT_Z_AXIS;
93        else                                                                  _cachedMode = ROTATE_TO_AXIS;
94    }
95    else _cachedMode = _autoRotateMode;
96
97    _side = _axis^_normal;
98    _side.normalize();
99}
100
101void AutoTransform::setScale(const Vec3d& scale)
102{
103    _scale = scale;
104    if (_scale.x()<_minimumScale) _scale.x() = _minimumScale;
105    if (_scale.y()<_minimumScale) _scale.y() = _minimumScale;
106    if (_scale.z()<_minimumScale) _scale.z() = _minimumScale;
107
108    if (_scale.x()>_maximumScale) _scale.x() = _maximumScale;
109    if (_scale.y()>_maximumScale) _scale.y() = _maximumScale;
110    if (_scale.z()>_maximumScale) _scale.z() = _maximumScale;
111
112    _matrixDirty=true;
113    dirtyBound();
114}
115
116
117bool AutoTransform::computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*) const
118{
119    if (_matrixDirty) computeMatrix();
120
121    if (_referenceFrame==RELATIVE_RF)
122    {
123        matrix.preMult(_cachedMatrix);
124    }
125    else // absolute
126    {
127        matrix = _cachedMatrix;
128    }
129    return true;
130}
131
132
133bool AutoTransform::computeWorldToLocalMatrix(Matrix& matrix,NodeVisitor*) const
134{
135    if (_scale.x() == 0.0 || _scale.y() == 0.0 || _scale.z() == 0.0)
136        return false;
137
138    if (_referenceFrame==RELATIVE_RF)
139    {
140        matrix.postMultTranslate(-_position);
141        matrix.postMultRotate(_rotation.inverse());
142        matrix.postMultScale(Vec3d(1.0/_scale.x(), 1.0/_scale.y(), 1.0/_scale.z()));
143        matrix.postMultTranslate(_pivotPoint);
144    }
145    else // absolute
146    {
147        matrix.makeRotate(_rotation.inverse());
148        matrix.preMultTranslate(-_position);
149        matrix.postMultScale(Vec3d(1.0/_scale.x(), 1.0/_scale.y(), 1.0/_scale.z()));
150        matrix.postMultTranslate(_pivotPoint);
151    }
152    return true;
153}
154
155void AutoTransform::computeMatrix() const
156{
157    if (!_matrixDirty) return;
158
159    _cachedMatrix.makeRotate(_rotation);
160    _cachedMatrix.postMultTranslate(_position);
161    _cachedMatrix.preMultScale(_scale);
162    _cachedMatrix.preMultTranslate(-_pivotPoint);
163
164    _matrixDirty = false;
165}
166
167void AutoTransform::accept(NodeVisitor& nv)
168{
169    if (nv.validNodeMask(*this))
170    {
171        // if app traversal update the frame count.
172        if (nv.getVisitorType()==NodeVisitor::UPDATE_VISITOR)
173        {
174        }
175        else
176        if (nv.getVisitorType()==NodeVisitor::CULL_VISITOR)
177        {
178
179            CullStack* cs = dynamic_cast<CullStack*>(&nv);
180            if (cs)
181            {
182
183                Viewport::value_type width = _previousWidth;
184                Viewport::value_type height = _previousHeight;
185
186                osg::Viewport* viewport = cs->getViewport();
187                if (viewport)
188                {
189                    width = viewport->width();
190                    height = viewport->height();
191                }
192
193                osg::Vec3d eyePoint = cs->getEyeLocal();
194                osg::Vec3d localUp = cs->getUpLocal();
195                osg::Vec3d position = getPosition();
196
197                const osg::Matrix& projection = *(cs->getProjectionMatrix());
198
199                bool doUpdate = _firstTimeToInitEyePoint;
200                if (!_firstTimeToInitEyePoint)
201                {
202                    osg::Vec3d dv = _previousEyePoint-eyePoint;
203                    if (dv.length2()>getAutoUpdateEyeMovementTolerance()*(eyePoint-getPosition()).length2())
204                    {
205                        doUpdate = true;
206                    }
207                    osg::Vec3d dupv = _previousLocalUp-localUp;
208                    // rotating the camera only affects ROTATE_TO_*
209                    if (_autoRotateMode &&
210                        dupv.length2()>getAutoUpdateEyeMovementTolerance())
211                    {
212                        doUpdate = true;
213                    }
214                    else if (width!=_previousWidth || height!=_previousHeight)
215                    {
216                        doUpdate = true;
217                    }
218                    else if (projection != _previousProjection)
219                    {
220                        doUpdate = true;
221                    }
222                    else if (position != _previousPosition)
223                    {
224                        doUpdate = true;
225                    }
226                }
227                _firstTimeToInitEyePoint = false;
228
229                if (doUpdate)
230                {
231
232                    if (getAutoScaleToScreen())
233                    {
234                        double size = 1.0/cs->pixelSize(getPosition(),0.48f);
235
236                        if (_autoScaleTransitionWidthRatio>0.0)
237                        {
238                            if (_minimumScale>0.0)
239                            {
240                                double j = _minimumScale;
241                                double i = (_maximumScale<DBL_MAX) ?
242                                            _minimumScale+(_maximumScale-_minimumScale)*_autoScaleTransitionWidthRatio :
243                                            _minimumScale*(1.0+_autoScaleTransitionWidthRatio);
244                                double c = 1.0/(4.0*(i-j));
245                                double b = 1.0 - 2.0*c*i;
246                                double a = j + b*b / (4.0*c);
247                                double k = -b / (2.0*c);
248
249                                if (size<k) size = _minimumScale;
250                                else if (size<i) size = a + b*size + c*(size*size);
251                            }
252
253                            if (_maximumScale<DBL_MAX)
254                            {
255                                double n = _maximumScale;
256                                double m = (_minimumScale>0.0) ?
257                                            _maximumScale+(_minimumScale-_maximumScale)*_autoScaleTransitionWidthRatio :
258                                            _maximumScale*(1.0-_autoScaleTransitionWidthRatio);
259                                double c = 1.0 / (4.0*(m-n));
260                                double b = 1.0 - 2.0*c*m;
261                                double a = n + b*b/(4.0*c);
262                                double p = -b / (2.0*c);
263
264                                if (size>p) size = _maximumScale;
265                                else if (size>m) size = a + b*size + c*(size*size);
266                            }
267                        }
268
269                        setScale(size);
270                    }
271
272                    if (_autoRotateMode==ROTATE_TO_SCREEN)
273                    {
274                        osg::Vec3d translation;
275                        osg::Quat rotation;
276                        osg::Vec3d scale;
277                        osg::Quat so;
278
279                        cs->getModelViewMatrix()->decompose( translation, rotation, scale, so );
280
281                        setRotation(rotation.inverse());
282                    }
283                    else if (_autoRotateMode==ROTATE_TO_CAMERA)
284                    {
285                        osg::Vec3d PosToEye = _position - eyePoint;
286                        osg::Matrix lookto = osg::Matrix::lookAt(
287                            osg::Vec3d(0,0,0), PosToEye, localUp);
288                        Quat q;
289                        q.set(osg::Matrix::inverse(lookto));
290                        setRotation(q);
291                    }
292                    else if (_autoRotateMode==ROTATE_TO_AXIS)
293                    {
294                        Matrix matrix;
295                        Vec3 ev(eyePoint - _position);
296
297                        switch(_cachedMode)
298                        {
299                            case(AXIAL_ROT_Z_AXIS):
300                            {
301                                ev.z() = 0.0f;
302                                float ev_length = ev.length();
303                                if (ev_length>0.0f)
304                                {
305                                    //float rotation_zrotation_z = atan2f(ev.x(),ev.y());
306                                    //mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f);
307                                    float inv = 1.0f/ev_length;
308                                    float s = ev.x()*inv;
309                                    float c = -ev.y()*inv;
310                                    matrix(0,0) = c;
311                                    matrix(1,0) = -s;
312                                    matrix(0,1) = s;
313                                    matrix(1,1) = c;
314                                }
315                                break;
316                            }
317                            case(AXIAL_ROT_Y_AXIS):
318                            {
319                                ev.y() = 0.0f;
320                                float ev_length = ev.length();
321                                if (ev_length>0.0f)
322                                {
323                                    //float rotation_zrotation_z = atan2f(ev.x(),ev.y());
324                                    //mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f);
325                                    float inv = 1.0f/ev_length;
326                                    float s = -ev.z()*inv;
327                                    float c = ev.x()*inv;
328                                    matrix(0,0) = c;
329                                    matrix(2,0) = s;
330                                    matrix(0,2) = -s;
331                                    matrix(2,2) = c;
332                                }
333                                break;
334                            }
335                            case(AXIAL_ROT_X_AXIS):
336                            {
337                                ev.x() = 0.0f;
338                                float ev_length = ev.length();
339                                if (ev_length>0.0f)
340                                {
341                                    //float rotation_zrotation_z = atan2f(ev.x(),ev.y());
342                                    //mat.makeRotate(inRadians(rotation_z),0.0f,0.0f,1.0f);
343                                    float inv = 1.0f/ev_length;
344                                    float s = -ev.z()*inv;
345                                    float c = -ev.y()*inv;
346                                    matrix(1,1) = c;
347                                    matrix(2,1) = -s;
348                                    matrix(1,2) = s;
349                                    matrix(2,2) = c;
350                                }
351                                break;
352                            }
353                            case(ROTATE_TO_AXIS): // need to implement
354                            {
355                                float ev_side = ev*_side;
356                                float ev_normal = ev*_normal;
357                                float rotation = atan2f(ev_side,ev_normal);
358                                matrix.makeRotate(rotation,_axis);
359                                break;
360                            }
361                        }
362                        Quat q;
363                        q.set(matrix);
364                        setRotation(q);
365                    }
366
367                    _previousEyePoint = eyePoint;
368                    _previousLocalUp = localUp;
369                    _previousWidth = width;
370                    _previousHeight = height;
371                    _previousProjection = projection;
372                    _previousPosition = position;
373
374                    _matrixDirty = true;
375                }
376
377            }
378        }
379
380        // now do the proper accept
381        Transform::accept(nv);
382    }
383}
384
385BoundingSphere AutoTransform::computeBound() const
386{
387    BoundingSphere bsphere;
388
389    if ( getAutoScaleToScreen() && _firstTimeToInitEyePoint )
390        return bsphere;
391
392    bsphere = Transform::computeBound();
393
394    return bsphere;
395}
Note: See TracBrowser for help on using the browser.