Fix Translate axis animation Refs ticket #2706

Due to an error I made in 7ac90850 all AxisObject-based translate animations were inverted.

I think this correctly fixes the animations so that a value of zero is the 'start' vertex of the axis and a value of 1.0 is the 'end' value of the axis.

Start and end are now defined on the lowest x,y,z that aren't equivalent (within 0.01mm)

see: https://sourceforge.net/p/flightgear/codetickets/2706/
This commit is contained in:
Richard Harrison 2022-03-14 16:58:12 +01:00
parent 83eda09558
commit 91eca221f9
2 changed files with 47 additions and 30 deletions

View File

@ -125,15 +125,25 @@ public:
{ {
return _lineSegments; return _lineSegments;
} }
// instead of using the lowest X to instead find the lowest of all (x,y,z) and use this
// see https://sourceforge.net/p/flightgear/codetickets/2706/
bool compareVec3(const osg::Vec3& v1, const osg::Vec3& v2) {
// compare to the nearest 0.01mm
if (abs(v2[0]-v1[0]) > 0.00001)
return v2[0] < v1[0];
else if (abs(v2[1] - v1[1]) > 0.00001)
return v2[1] < v1[1];
else
return v2[2] < v1[2];
}
void addLine(const osg::Vec3& v1, const osg::Vec3& v2) void addLine(const osg::Vec3& v1, const osg::Vec3& v2)
{ {
// Trick to get the ends in the right order.
// Use the x axis in the original coordinate system. Choose the
// most negative x-axis as the one pointing forward
SGVec3f tv1(toSG(_matrix.preMult(v1))); SGVec3f tv1(toSG(_matrix.preMult(v1)));
SGVec3f tv2(toSG(_matrix.preMult(v2))); SGVec3f tv2(toSG(_matrix.preMult(v2)));
if (tv1[0] > tv2[0])
// Get the ends in the right order based on their
// lowest coordinates in x,y,z
if (compareVec3(v1, v2))
_lineSegments.push_back(SGLineSegmentf(tv1, tv2)); _lineSegments.push_back(SGLineSegmentf(tv1, tv2));
else else
_lineSegments.push_back(SGLineSegmentf(tv2, tv1)); _lineSegments.push_back(SGLineSegmentf(tv2, tv1));
@ -434,6 +444,7 @@ SGAnimation::SGAnimation(simgear::SGTransientModelData &modelData) :
{ {
_name = modelData.getConfigNode()->getStringValue("name", ""); _name = modelData.getConfigNode()->getStringValue("name", "");
_enableHOT = modelData.getConfigNode()->getBoolValue("enable-hot", true); _enableHOT = modelData.getConfigNode()->getBoolValue("enable-hot", true);
std::vector<SGPropertyNode_ptr> objectNames = std::vector<SGPropertyNode_ptr> objectNames =
modelData.getConfigNode()->getChildren("object-name"); modelData.getConfigNode()->getChildren("object-name");
for (unsigned i = 0; i < objectNames.size(); ++i) for (unsigned i = 0; i < objectNames.size(); ++i)
@ -714,7 +725,7 @@ protected:
* This function will take action when axis has an object-name tag and the corresponding object * This function will take action when axis has an object-name tag and the corresponding object
* can be found within the hierarchy. * can be found within the hierarchy.
*/ */
bool SGAnimation::setCenterAndAxisFromObject(osg::Node *rootNode, SGVec3d& center, SGVec3d &axis, SGVec3d &offset, simgear::SGTransientModelData &modelData) const const SGLineSegment<double>* SGAnimation::setCenterAndAxisFromObject(osg::Node *rootNode, SGVec3d& center, SGVec3d &axis, simgear::SGTransientModelData &modelData) const
{ {
std::string axis_object_name = std::string(); std::string axis_object_name = std::string();
bool can_warn = true; bool can_warn = true;
@ -746,7 +757,6 @@ bool SGAnimation::setCenterAndAxisFromObject(osg::Node *rootNode, SGVec3d& cente
FindGroupVisitor axis_object_name_finder(axis_object_name); FindGroupVisitor axis_object_name_finder(axis_object_name);
rootNode->accept(axis_object_name_finder); rootNode->accept(axis_object_name_finder);
osg::Group *object_group = axis_object_name_finder.getGroup(); osg::Group *object_group = axis_object_name_finder.getGroup();
if (object_group) if (object_group)
{ {
/* /*
@ -792,13 +802,12 @@ bool SGAnimation::setCenterAndAxisFromObject(osg::Node *rootNode, SGVec3d& cente
} }
if (axisSegment) if (axisSegment)
{ {
offset = axisSegment->getStart() - axisSegment->getEnd();
center = 0.5*(axisSegment->getStart() + axisSegment->getEnd()); center = 0.5*(axisSegment->getStart() + axisSegment->getEnd());
axis = axisSegment->getEnd() - axisSegment->getStart(); axis = axisSegment->getEnd() - axisSegment->getStart();
return true; return axisSegment;
} }
} }
return false; return nullptr;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// factored out to share with SGKnobAnimation // factored out to share with SGKnobAnimation
@ -806,8 +815,7 @@ void SGAnimation::readRotationCenterAndAxis(osg::Node *_rootNode, SGVec3d& cente
SGVec3d& axis, simgear::SGTransientModelData &modelData) const SGVec3d& axis, simgear::SGTransientModelData &modelData) const
{ {
center = SGVec3d::zeros(); center = SGVec3d::zeros();
SGVec3d offsets; if (setCenterAndAxisFromObject(_rootNode, center, axis, modelData))
if (setCenterAndAxisFromObject(_rootNode, center, axis, offsets, modelData))
{ {
if (8 * SGLimitsd::min() < norm(axis)) if (8 * SGLimitsd::min() < norm(axis))
axis = normalize(axis); axis = normalize(axis);
@ -961,24 +969,33 @@ public:
SGTranslateAnimation::SGTranslateAnimation(simgear::SGTransientModelData &modelData) : SGTranslateAnimation::SGTranslateAnimation(simgear::SGTransientModelData &modelData) :
SGAnimation(modelData) SGAnimation(modelData)
{ {
_condition = getCondition(); _condition = getCondition();
SGSharedPtr<SGExpressiond> value; SGSharedPtr<SGExpressiond> value;
value = read_value(modelData.getConfigNode(), modelData.getModelRoot(), "-m",
-SGLimitsd::max(), SGLimitsd::max());
if (!value) {
throw sg_format_exception("Invalid translate expression", "Value is not readable");
}
_animationValue = value->simplify();
if (_animationValue)
_initialValue = _animationValue->getValue();
else
_initialValue = 0;
SGVec3d _center, _offsets; value = read_value(modelData.getConfigNode(), modelData.getModelRoot(), "-m",
if (modelData.getNode() && !setCenterAndAxisFromObject(modelData.getNode(), _center, _axis, _offsets, modelData)) -SGLimitsd::max(), SGLimitsd::max());
_axis = readTranslateAxis(modelData.getConfigNode()); if (!value) {
else throw sg_format_exception("Invalid translate expression", "Value is not readable");
_axis = _offsets; }
_animationValue = value->simplify();
if (_animationValue)
_initialValue = _animationValue->getValue();
else
_initialValue = 0;
SGVec3d _center;
if (modelData.getNode())
{
auto segment = setCenterAndAxisFromObject(modelData.getNode(), _center, _axis, modelData);
if (segment) {
_center = segment->getStart();
_axis = segment->getEnd() - segment->getStart();
}
else {
_axis = readTranslateAxis(modelData.getConfigNode());
}
}
} }
osg::Group* osg::Group*

View File

@ -82,7 +82,7 @@ protected:
const SGVec3d& def = SGVec3d::zeros() ) const; const SGVec3d& def = SGVec3d::zeros() ) const;
void readRotationCenterAndAxis(osg::Node *rootNode, SGVec3d& center, SGVec3d& axis, simgear::SGTransientModelData &modelData) const; void readRotationCenterAndAxis(osg::Node *rootNode, SGVec3d& center, SGVec3d& axis, simgear::SGTransientModelData &modelData) const;
bool setCenterAndAxisFromObject(osg::Node *rootNode, SGVec3d& center, SGVec3d &axis, SGVec3d& offset, simgear::SGTransientModelData &modelData) const; const SGLineSegment<double>* setCenterAndAxisFromObject(osg::Node *rootNode, SGVec3d& center, SGVec3d &axis, simgear::SGTransientModelData &modelData) const;
SGExpressiond* readOffsetValue(const char* tag_name) const; SGExpressiond* readOffsetValue(const char* tag_name) const;