Files
OpenSceneGraph/src/osgManipulator/Constraint.cpp
Robert Osfield 19db0c1674 From Vivek Rajan, new osgManipulator library, with a few minor tweaks and rename for osgDragger to osgManipulator for build by Robert Osfield.
Vivek's email to osg-submissions:

"I'm happy to release the osgdragger nodekit to the OSG community. I
implemented the nodekit for my company, Fugro-Jason Inc., and they
have kindly agreed to open source it.

The nodekit contains a few draggers but it should be easy to build new
draggers on top of it. The design of the nodekit is based on a
SIGGRAPH 2002 course - "Design and Implementation of Direct
Manipulation in 3D". You can find the course notes at
http://www.pauliface.com/Sigg02/index.html. Reading pages 20 - 29 of
the course notes should give you a fair understanding of how the
nodekit works.

The source code also contains an example of how to use the draggers."
2007-02-11 10:33:59 +00:00

166 lines
7.1 KiB
C++

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
//osgManipulator - Copyright (C) 2007 Fugro-Jason B.V.
#include <osgManipulator/Constraint>
#include <osgManipulator/Command>
#include <osg/Vec2d>
#include <math.h>
using namespace osgManipulator;
namespace
{
double round_to_nearest_int(double x) { return floor(x+0.5); }
osg::Vec3d snap_point_to_grid(const osg::Vec3d& point, const osg::Vec3d& origin, const osg::Vec3d& spacing)
{
osg::Vec3d scale;
scale[0] = spacing[0] ? round_to_nearest_int((point[0] - origin[0]) / spacing[0]) : 1.0;
scale[1] = spacing[1] ? round_to_nearest_int((point[1] - origin[1]) / spacing[1]) : 1.0;
scale[2] = spacing[2] ? round_to_nearest_int((point[2] - origin[2]) / spacing[2]) : 1.0;
osg::Vec3d snappedPoint = origin;
snappedPoint += osg::Vec3(scale[0]*spacing[0],scale[1]*spacing[1],scale[2]*spacing[2]);
return snappedPoint;
}
}
void Constraint::computeLocalToWorldAndWorldToLocal() const
{
osg::NodePath pathToRoot;
computeNodePathToRoot(const_cast<osg::Node&>(getReferenceNode()),pathToRoot);
_localToWorld = osg::computeLocalToWorld(pathToRoot);
_worldToLocal = osg::computeWorldToLocal(pathToRoot);
}
GridConstraint::GridConstraint(osg::Node& refNode, const osg::Vec3d& origin, const osg::Vec3d& spacing)
: Constraint(refNode), _origin(origin), _spacing(spacing)
{
}
bool GridConstraint::constrain(TranslateInLineCommand& command) const
{
if (command.getStage() == osgManipulator::MotionCommand::START)
computeLocalToWorldAndWorldToLocal();
else if (command.getStage() == osgManipulator::MotionCommand::FINISH)
return true;
osg::Vec3 translatedPoint = command.getLineStart() + command.getTranslation();
osg::Vec3d localTranslatedPoint = (osg::Vec3d(translatedPoint)
* command.getLocalToWorld() * getWorldToLocal());
osg::Vec3d newLocalTranslatedPoint = snap_point_to_grid(localTranslatedPoint,
_origin,
_spacing);
command.setTranslation(newLocalTranslatedPoint * getLocalToWorld() * command.getWorldToLocal() - command.getLineStart());
return true;
}
bool GridConstraint::constrain(TranslateInPlaneCommand& command) const
{
if (command.getStage() == osgManipulator::MotionCommand::START)
computeLocalToWorldAndWorldToLocal();
else if (command.getStage() == osgManipulator::MotionCommand::FINISH)
return true;
osg::Matrix commandToConstraint = command.getLocalToWorld() * getWorldToLocal();
osg::Matrix constraintToCommand = getLocalToWorld() * command.getWorldToLocal();
// Snap the reference point to grid.
osg::Vec3d localRefPoint = command.getReferencePoint() * commandToConstraint;
osg::Vec3d snappedLocalRefPoint = snap_point_to_grid(localRefPoint, _origin, _spacing);
osg::Vec3d snappedCmdRefPoint = snappedLocalRefPoint * constraintToCommand;
// Snap the translated point to grid.
osg::Vec3 translatedPoint = snappedCmdRefPoint + command.getTranslation();
osg::Vec3d localTranslatedPoint = osg::Vec3d(translatedPoint) * commandToConstraint;
osg::Vec3d newLocalTranslatedPoint = snap_point_to_grid(localTranslatedPoint, _origin, _spacing);
// Set the snapped translation.
command.setTranslation(newLocalTranslatedPoint * constraintToCommand - snappedCmdRefPoint);
return true;
}
bool GridConstraint::constrain(Scale1DCommand& command) const
{
if (command.getStage() == osgManipulator::MotionCommand::START)
computeLocalToWorldAndWorldToLocal();
else if (command.getStage() == osgManipulator::MotionCommand::FINISH)
return true;
double scaledPoint = (command.getReferencePoint() - command.getScaleCenter()) * command.getScale() + command.getScaleCenter();
osg::Matrix constraintToCommand = getLocalToWorld() * command.getWorldToLocal();
osg::Vec3d commandOrigin = _origin * constraintToCommand;
osg::Vec3d commandSpacing = (_origin + _spacing) * constraintToCommand - commandOrigin;
double spacingFactor = commandSpacing[0] ? round_to_nearest_int((scaledPoint-commandOrigin[0])/commandSpacing[0]) : 1.0;
double snappedScaledPoint = commandOrigin[0] + commandSpacing[0] * spacingFactor;
double denom = (command.getReferencePoint() - command.getScaleCenter());
double snappedScale = (denom) ? (snappedScaledPoint - command.getScaleCenter()) / denom : 1.0;
if (snappedScale < command.getMinScale()) snappedScale = command.getMinScale();
command.setScale(snappedScale);
return true;
}
bool GridConstraint::constrain(Scale2DCommand& command) const
{
if (command.getStage() == osgManipulator::MotionCommand::START)
computeLocalToWorldAndWorldToLocal();
else if (command.getStage() == osgManipulator::MotionCommand::FINISH)
return true;
osg::Vec2d scaledPoint = command.getReferencePoint() - command.getScaleCenter();
scaledPoint[0] *= command.getScale()[0];
scaledPoint[1] *= command.getScale()[1];
scaledPoint += command.getScaleCenter();
osg::Matrix constraintToCommand = getLocalToWorld() * command.getWorldToLocal();
osg::Vec3d commandOrigin = _origin * constraintToCommand;
osg::Vec3d commandSpacing = (_origin + _spacing) * constraintToCommand - commandOrigin;
osg::Vec2d spacingFactor;
spacingFactor[0] = commandSpacing[0] ? round_to_nearest_int((scaledPoint[0] - commandOrigin[0])/commandSpacing[0]) : 1.0;
spacingFactor[1] = commandSpacing[2] ? round_to_nearest_int((scaledPoint[1] - commandOrigin[2])/commandSpacing[2]) : 1.0;
osg::Vec2d snappedScaledPoint = (osg::Vec2d(commandOrigin[0],commandOrigin[2])
+ osg::Vec2d(commandSpacing[0]*spacingFactor[0],
commandSpacing[2]*spacingFactor[1]));
osg::Vec2d denom = command.getReferencePoint() - command.getScaleCenter();
osg::Vec2 snappedScale;
snappedScale[0] = denom[0] ? (snappedScaledPoint[0] - command.getScaleCenter()[0]) / denom[0] : 1.0;
snappedScale[1] = denom[1] ? (snappedScaledPoint[1] - command.getScaleCenter()[1]) / denom[1] : 1.0;
if (snappedScale[0] < command.getMinScale()[0]) snappedScale[0] = command.getMinScale()[0];
if (snappedScale[1] < command.getMinScale()[1]) snappedScale[1] = command.getMinScale()[1];
command.setScale(snappedScale);
return true;
}
bool GridConstraint::constrain(ScaleUniformCommand&) const
{
// Can you correctly snap a ScaleUniformCommand using a Grid constraint that has
// different spacings in the three axis??
return false;
}