Added new osg::DOFTransform node from Sasa Bistrovic, designed to mirror

the OpenFlight DOF transform nodes.
This commit is contained in:
Robert Osfield
2002-08-05 15:07:18 +00:00
parent 6c998bf97d
commit 25740b5c7f
6 changed files with 676 additions and 1 deletions

382
src/osg/DOFTransform.cpp Normal file
View File

@@ -0,0 +1,382 @@
#include <osg/DOFTransform>
#include <osgUtil/CullVisitor>
#include <osgUtil/AppVisitor>
using namespace osg;
struct DOFCullCallback : public Transform::ComputeTransformCallback
{
/**/
virtual const bool computeLocalToWorldMatrix(Matrix& matrix, const Transform* trans, NodeVisitor* nv) const
{
osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
if(cv)
{
const DOFTransform* dof = dynamic_cast<const DOFTransform*>(trans);
if(dof)
{
//here we are:
//put the PUT matrix first:
Matrix l2w(dof->getPutMatrix());
//now the current matrix:
Matrix current;
current.makeTranslate(dof->getCurrentTranslate());
//now create the local rotation:
current.preMult(Matrix::rotate(dof->getCurrentHPR()[1], 1.0, 0.0, 0.0));//pitch
current.preMult(Matrix::rotate(dof->getCurrentHPR()[2], 0.0, 1.0, 0.0));//roll
current.preMult(Matrix::rotate(dof->getCurrentHPR()[0], 0.0, 0.0, 1.0));//heading
//and scale:
current.preMult(Matrix::scale(dof->getCurrentScale()));
l2w.postMult(current);
//and impose inverse put:
l2w.postMult(dof->getInversePutMatrix());
//finally:
matrix.preMult(l2w);
}
}
return true;
}
/**/
virtual const bool computeWorldToLocalMatrix(Matrix& matrix, const Transform* trans, NodeVisitor* nv) const
{
osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
if(cv)
{
const DOFTransform* dof = dynamic_cast<const DOFTransform*>(trans);
if(dof)
{
//here we are:
//put the PUT matrix first:
Matrix w2l(dof->getInversePutMatrix());
//now the current matrix:
Matrix current;
current.makeTranslate(-dof->getCurrentTranslate());
//now create the local rotation:
current.postMult(Matrix::rotate(-dof->getCurrentHPR()[0], 0.0, 0.0, 1.0));//heading
current.postMult(Matrix::rotate(-dof->getCurrentHPR()[2], 0.0, 1.0, 0.0));//roll
current.postMult(Matrix::rotate(-dof->getCurrentHPR()[1], 1.0, 0.0, 0.0));//pitch
//and scale:
current.postMult(Matrix::scale(1./dof->getCurrentScale()[0], 1./dof->getCurrentScale()[1], 1./dof->getCurrentScale()[2]));
w2l.postMult(current);
//and impose inverse put:
w2l.postMult(dof->getPutMatrix());
//finally:
matrix.postMult(w2l);
}
}
return true;
}
};
class DOFAnimationAppCallback : public osg::NodeCallback
{
/** Callback method call by the NodeVisitor when visiting a node.*/
virtual void operator()(Node* node, NodeVisitor* nv)
{
//this is aspp visitor, see if we have DOFTransform:
DOFTransform* dof = dynamic_cast<DOFTransform*>(node);
if(dof)
{
//see if it is ina animation mode:
dof->animate();
}
// note, callback is repsonsible for scenegraph traversal so
// should always include call the traverse(node,nv) to ensure
// that the rest of cullbacks and the scene graph are traversed.
traverse(node,nv);
}
};
DOFTransform::DOFTransform():
_limitationFlags(0),
_animationOn(false),
_increasingFlags(0xffffff)
{
//default zero-ed Vec3-s are fine for all
//default idenetiy inverse matrix is fine:
_computeTransformCallback = new DOFCullCallback;
DOFAnimationAppCallback* dof_animation = new DOFAnimationAppCallback;
setAppCallback(dof_animation);
}
void DOFTransform::setCurrentHPR(const Vec3& hpr)
{
//if there is no constrain on animation
if(!(_limitationFlags & ((unsigned long)1<<26)))
{
//if we have min == max, it is efective constrain, so don't change
if(_minHPR[2] != _maxHPR[2])
{
_currentHPR[2] = hpr[2];
unsigned short this_flag = (unsigned short)1<<4;//roll
if(_currentHPR[2] < _minHPR[2])
{
_currentHPR[2] = _minHPR[2];
//force increasing flag to 1
_increasingFlags |= this_flag;
}
else if(_currentHPR[2] > _maxHPR[2])
{
_currentHPR[2] = _maxHPR[2];
//force increasing flag to 0
_increasingFlags &= ~this_flag;
}
}
}
if(!(_limitationFlags & ((unsigned long)1<<27)))
{
if(_minHPR[1] != _maxHPR[1])
{
_currentHPR[1] = hpr[1];
unsigned short this_flag = (unsigned short)1<<3;//pitch
if(_currentHPR[1] < _minHPR[1])
{
_currentHPR[1] = _minHPR[1];
_increasingFlags |= this_flag;
}
else if(_currentHPR[1] > _maxHPR[1])
{
_currentHPR[1] = _maxHPR[1];
_increasingFlags &= ~this_flag;
}
}
}
if(!(_limitationFlags & ((unsigned long)1<<28)))
{
if(_minHPR[0] != _maxHPR[0])
{
_currentHPR[0] = hpr[0];
unsigned short this_flag = (unsigned short)1<<5;//heading
if(_currentHPR[0] < _minHPR[0])
{
_currentHPR[0] = _minHPR[0];
_increasingFlags |= this_flag;
}
else if(_currentHPR[0] > _maxHPR[0])
{
_currentHPR[0] = _maxHPR[0];
_increasingFlags &= ~this_flag;
}
}
}
}
void DOFTransform::setCurrentTranslate(const Vec3& translate)
{
if(!(_limitationFlags & (unsigned long)1<<29))
{
if(_minTranslate[2] != _maxTranslate[2])
{
_currentTranslate[2] = translate[2];
unsigned short this_flag = (unsigned short)1<<2;
if(_currentTranslate[2] < _minTranslate[2])
{
_currentTranslate[2] = _minTranslate[2];
_increasingFlags |= this_flag;
}
else if(_currentTranslate[2] > _maxTranslate[2])
{
_currentTranslate[2] = _maxTranslate[2];
_increasingFlags &= ~this_flag;
}
}
}
if(!(_limitationFlags & (unsigned long)1<<30))
{
if(_minTranslate[1] != _maxTranslate[1])
{
_currentTranslate[1] = translate[1];
unsigned short this_flag = (unsigned short)1<<1;
if(_currentTranslate[1] < _minTranslate[1])
{
_currentTranslate[1] = _minTranslate[1];
_increasingFlags |= this_flag;
}
else if(_currentTranslate[1] > _maxTranslate[1])
{
_currentTranslate[1] = _maxTranslate[1];
_increasingFlags &= ~this_flag;
}
}
}
if(!(_limitationFlags & (unsigned long)1<<31))
{
if(_minTranslate[0] != _maxTranslate[0])
{
_currentTranslate[0] = translate[0];
unsigned short this_flag = (unsigned short)1;
if(_currentTranslate[0] < _minTranslate[0])
{
_currentTranslate[0] = _minTranslate[0];
_increasingFlags |= this_flag;
}
else if(_currentTranslate[0] > _maxTranslate[0])
{
_currentTranslate[0] = _maxTranslate[0];
_increasingFlags &= ~this_flag;
}
}
}
}
void DOFTransform::setCurrentScale(const Vec3& scale)
{
if(!(_limitationFlags & ((unsigned long)1<<23)))
{
if(_minScale[2] != _maxScale[2])
{
_currentScale[2] = scale[2];
unsigned short this_flag = (unsigned short)1<<8;
if(_currentScale[2] < _minScale[2])
{
_currentScale[2] = _minScale[2];
_increasingFlags |= this_flag;
}
else if(_currentScale[2] > _maxScale[2])
{
_currentScale[2] = _maxScale[2];
_increasingFlags &= ~this_flag;
}
}
}
if(!(_limitationFlags & ((unsigned long)1<<24)))
{
if(_minScale[1] != _maxScale[1])
{
_currentScale[1] = scale[1];
unsigned short this_flag = (unsigned short)1<<7;
if(_currentScale[1] < _minScale[1])
{
_currentScale[1] = _minScale[1];
_increasingFlags |= this_flag;
}
else if(_currentScale[1] > _maxScale[1])
{
_currentScale[1] = _maxScale[1];
_increasingFlags &= ~this_flag;
}
}
}
if(!(_limitationFlags & ((unsigned long)1<<25)))
{
if(_minScale[0] != _maxScale[0])
{
_currentScale[0] = scale[0];
unsigned short this_flag = (unsigned short)1<<6;
if(_currentScale[0] < _minScale[0])
{
_currentScale[0] = _minScale[0];
_increasingFlags |= this_flag;
}
else if(_currentScale[0] > _maxScale[0])
{
_currentScale[0] = _maxScale[0];
_increasingFlags &= ~this_flag;
}
}
}
}
void DOFTransform::animate()
{
if(!_animationOn) return;
//this will increment or decrement all allowed values
Vec3 new_value = _currentTranslate;
if(_increasingFlags & 1)
new_value[0] += _incrementTranslate[0];
else
new_value[0] -= _incrementTranslate[0];
if(_increasingFlags & 1<<1)
new_value[1] += _incrementTranslate[1];
else
new_value[1] -= _incrementTranslate[1];
if(_increasingFlags & 1<<2)
new_value[2] += _incrementTranslate[2];
else
new_value[2] -= _incrementTranslate[2];
setCurrentTranslate(new_value);
new_value = _currentHPR;
if(_increasingFlags & ((unsigned short)1<<3))
new_value[1] += _incrementHPR[1];
else
new_value[1] -= _incrementHPR[1];
if(_increasingFlags & ((unsigned short)1<<4))
new_value[2] += _incrementHPR[2];
else
new_value[2] -= _incrementHPR[2];
if(_increasingFlags & ((unsigned short)1<<5))
new_value[0] += _incrementHPR[0];
else
new_value[0] -= _incrementHPR[0];
setCurrentHPR(new_value);
new_value = _currentScale;
if(_increasingFlags & 1<<6)
new_value[0] += _incrementScale[0];
else
new_value[0] -= _incrementScale[0];
if(_increasingFlags & 1<<7)
new_value[1] += _incrementScale[1];
else
new_value[1] -= _incrementScale[1];
if(_increasingFlags & 1<<8)
new_value[2] += _incrementScale[2];
else
new_value[2] -= _incrementScale[2];
setCurrentScale(new_value);
}

View File

@@ -23,6 +23,7 @@ CXXFILES =\
CullStack.cpp\
Depth.cpp\
DisplaySettings.cpp\
DOFTransform.cpp\
Drawable.cpp\
DrawPixels.cpp\
EarthSky.cpp\

View File

@@ -23,6 +23,8 @@
#include <osg/Image>
#include <osg/Notify>
#include <osg/DOFTransform>
#include <osgDB/FileNameUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/ReadFile>
@@ -620,6 +622,146 @@ osg::Group* ConvertFromFLT::visitOldLOD(osg::Group& osgParent, OldLodRecord* rec
// Converted DOF to use transform - jtracy@ist.ucf.edu
osg::Group* ConvertFromFLT::visitDOF(osg::Group& osgParent, DofRecord* rec)
{
#if 1
osg::DOFTransform* transform = new osg::DOFTransform;
transform->setName(rec->getData()->szIdent);
transform->setDataVariance(osg::Object::DYNAMIC);
visitAncillary(osgParent, *transform, rec)->addChild( transform );
visitPrimaryNode(*transform, (PrimNodeRecord*)rec);
SDegreeOfFreedom* p_data = rec->getData();
//now fill up members:
//tranlsations:
transform->loadMinTranslate(osg::Vec3(_unitScale*p_data->dfX._dfMin,
_unitScale*p_data->dfY._dfMin,
_unitScale*p_data->dfZ._dfMin));
transform->loadMaxTranslate(osg::Vec3(_unitScale*p_data->dfX._dfMax,
_unitScale*p_data->dfY._dfMax,
_unitScale*p_data->dfZ._dfMax));
transform->loadCurrentTranslate(osg::Vec3(_unitScale*p_data->dfX._dfCurrent,
_unitScale*p_data->dfY._dfCurrent,
_unitScale*p_data->dfZ._dfCurrent));
transform->loadIncrementTranslate(osg::Vec3(_unitScale*p_data->dfX._dfIncrement,
_unitScale*p_data->dfY._dfIncrement,
_unitScale*p_data->dfZ._dfIncrement));
//rotations:
transform->loadMinHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfMin),
osg::inDegrees(p_data->dfPitch._dfMin),
osg::inDegrees(p_data->dfRoll._dfMin)));
transform->loadMaxHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfMax),
osg::inDegrees(p_data->dfPitch._dfMax),
osg::inDegrees(p_data->dfRoll._dfMax)));
transform->loadCurrentHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfCurrent),
osg::inDegrees(p_data->dfPitch._dfCurrent),
osg::inDegrees(p_data->dfRoll._dfCurrent)));
transform->loadIncrementHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfIncrement),
osg::inDegrees(p_data->dfPitch._dfIncrement),
osg::inDegrees(p_data->dfRoll._dfIncrement)));
//scales:
transform->loadMinScale(osg::Vec3(p_data->dfXscale._dfMin,
p_data->dfYscale._dfMin,
p_data->dfZscale._dfMin));
transform->loadMaxScale(osg::Vec3(p_data->dfXscale._dfMax,
p_data->dfYscale._dfMax,
p_data->dfZscale._dfMax));
transform->loadCurrentScale(osg::Vec3(p_data->dfXscale._dfCurrent,
p_data->dfYscale._dfCurrent,
p_data->dfZscale._dfCurrent));
transform->loadIncrementScale(osg::Vec3(p_data->dfXscale._dfIncrement,
p_data->dfYscale._dfIncrement,
p_data->dfZscale._dfIncrement));
//now calculate put and inverse put matrix:
//the translation matrix:
osg::Matrix l2g_translation;
//translation vector
osg::Vec3 origin_translation(p_data->OriginLocalDOF.x(), p_data->OriginLocalDOF.y(), p_data->OriginLocalDOF.z());
origin_translation *= _unitScale;//of course, has to be scaled to units used
//so we make translation matrix
l2g_translation.makeTranslate(origin_translation);
//now we need to construct rotation matrix that describes how is local coordinate system
//rotatoed in global:
osg::Matrix l2g_rotation;
//we make two normalized osg::Vec3s so we can cross-multiply them ....
//first we have "point on x axis", i.e. what the DOF local looks like in global
osg::Vec3 point_on_x_axis(p_data->PointOnXaxis.x(), p_data->PointOnXaxis.y(), p_data->PointOnXaxis.z());
point_on_x_axis *= _unitScale;
point_on_x_axis -= origin_translation;//we need to offset it for the origin
//second, we have "point in xy plane", so x ^ y gives us local z vector
osg::Vec3 point_in_xy_plane(p_data->PointInXYplane.x(), p_data->PointInXYplane.y(), p_data->PointInXYplane.z());
point_in_xy_plane *= _unitScale;
point_in_xy_plane -= origin_translation;//also offset it
//just in case, normalize them:
point_on_x_axis.normalize();
//now, local x in global is [1 0 0 1] * rotation_matrix, so we can directly write down first row
l2g_rotation.ptr()[0] = point_on_x_axis.x(); //that is mat[0][0]
l2g_rotation.ptr()[1] = point_on_x_axis.y(); //that is mat[0][1]
l2g_rotation.ptr()[2] = point_on_x_axis.z(); //that is mat[0][2]
//the cross product of x ^point_in_local_xy_plane gives local z
osg::Vec3 z_transformed = point_on_x_axis ^ point_in_xy_plane;
z_transformed.normalize();//we have to normalize it, and than we can directly writ it down to rotation matrix
//we can write it down to matrix directly:
l2g_rotation.ptr()[8] = z_transformed.x(); //that is mat[2][0]
l2g_rotation.ptr()[9] = z_transformed.y(); //that is mat[2][1]
l2g_rotation.ptr()[10] = z_transformed.z(); //that is mat[2][2]
//now that we have x and z, we can get y = z ^ x
osg::Vec3 y_transformed = z_transformed ^ point_on_x_axis;
//and just in case, we can normalize it:
// y_transformed.normalize();
//this goes to rotation matrix:
l2g_rotation.ptr()[4] = y_transformed.x(); //that is mat[1][0]
l2g_rotation.ptr()[5] = y_transformed.y(); //that is mat[1][0]
l2g_rotation.ptr()[6] = y_transformed.z(); //that is mat[1][0]
//now we have actually the second "PUT" transformation, and the first is inverse
osg::Matrix second_put = l2g_rotation * l2g_translation;
//and we take invers of it since it has to be done at the end, see FLT spec
osg::Matrix the_first = osg::Matrix::inverse(second_put);
transform->setPutMatrix(the_first);
transform->setInversePutMatrix(second_put);
/*
//and now do a little ENDIAN to put flags in ordewr as described in OpenFlight spec
unsigned long flags = p_data->dwFlags;
ENDIAN(flags);
//and setup limitation flags:
// transform->setLimitationFlags(flags);
*/
transform->setLimitationFlags(p_data->dwFlags);
return transform;
#else
osg::MatrixTransform* transform = new osg::MatrixTransform;
transform->setName(rec->getData()->szIdent);
@@ -690,6 +832,9 @@ osg::Group* ConvertFromFLT::visitDOF(osg::Group& osgParent, DofRecord* rec)
transform->setMatrix(dof_matrix);
return transform;
#endif
}