From 5e105d2fc40dd1883f0340032e97ca7a7b3af1f1 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 9 Mar 2012 10:20:23 +0000 Subject: [PATCH] From Chuck Seberino, "Attached are modified versions of RotateCylinderDragger and Projector files that clean up the use of _onCylinder / isProjectionOnCylinder(). I have also made changes to the RotateCylinderDragger to provide a cylinder ring with a thickness. It is totally optional, but IMHO makes the default behavior work better than a solid cylinder (which typically obscures the geometry you are trying to drag). Gives it a bit more to grab, especially in the case where eyepoint and cylinder axis are near parallel. " --- ChangeLog | 5 ++ include/osgManipulator/Projector | 21 ++++-- include/osgManipulator/RotateCylinderDragger | 1 - src/osgManipulator/Projector.cpp | 4 +- src/osgManipulator/RotateCylinderDragger.cpp | 79 ++++++++++++++++++-- 5 files changed, 95 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index dace1ec97..5bedf723d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-03-08 16:33 robert + + * CMakeLists.txt, ChangeLog, include/osg/Version: Updated version + number for 3.1.1 dev release + 2012-03-08 16:05 robert * include/osg/Image, src/osg/Image.cpp: From Farshid Lashkari, diff --git a/include/osgManipulator/Projector b/include/osgManipulator/Projector index 07e080a19..49c873722 100644 --- a/include/osgManipulator/Projector +++ b/include/osgManipulator/Projector @@ -263,7 +263,11 @@ class OSGMANIPULATOR_EXPORT CylinderProjector : public Projector }; /** - * CylinderPlaneProjector projects points onto the given cylinder. + * CylinderPlaneProjector projects a point onto a plane relative to the + * given cylinder. For most cases, the plane will be parallel to the + * cylinder axis oriented towards the eyepoint. When the eyepoint and + * cylinder axis are close to parallel, then it will project onto a plane + * perpendicular to the cylinder. */ class OSGMANIPULATOR_EXPORT CylinderPlaneProjector : public CylinderProjector { @@ -277,23 +281,26 @@ class OSGMANIPULATOR_EXPORT CylinderPlaneProjector : public CylinderProjector * Calculates the object coordinates (projectedPoint) of a window * coordinate (pointToProject) when projected onto the given plane. * Returns true on successful projection. + * \param[in] pi Incoming intersection information + * \param[out] projectedPoint Point located on the given plane + * \return bool Whether the projection onto the plane was successful. */ virtual bool project(const PointerInfo& pi, osg::Vec3d& projectedPoint) const; /** - * Returns true if the previous projection was on the cylinder and - * false if the projection was on the plane. + * Generates a rotation about the cylinder axis based upon the incoming + * projected points on the plane computed from project(). + * \param[in] p1 Initial projection point + * \param[in] p2 Second projection point + * \return osg::Quat Rotation about cylinder axis */ - bool isProjectionOnCylinder() const { return _onCylinder; } - - osg::Quat getRotation(const osg::Vec3d& p1, bool p1OnCyl, const osg::Vec3d& p2, bool p2OnCyl) const; + osg::Quat getRotation(const osg::Vec3d& p1, const osg::Vec3d& p2) const; protected: virtual ~CylinderPlaneProjector(); mutable osg::Plane _plane; - mutable bool _onCylinder; mutable osg::Vec3d _planeLineStart, _planeLineEnd; mutable bool _parallelPlane; }; diff --git a/include/osgManipulator/RotateCylinderDragger b/include/osgManipulator/RotateCylinderDragger index 318fbfb88..93eb27932 100644 --- a/include/osgManipulator/RotateCylinderDragger +++ b/include/osgManipulator/RotateCylinderDragger @@ -59,7 +59,6 @@ class OSGMANIPULATOR_EXPORT RotateCylinderDragger : public Dragger osg::ref_ptr _projector; osg::Vec3d _prevWorldProjPt; - bool _prevPtOnCylinder; osg::Matrix _startLocalToWorld, _startWorldToLocal; osg::Quat _prevRotation; diff --git a/src/osgManipulator/Projector.cpp b/src/osgManipulator/Projector.cpp index 14f487d3f..66cd0e94e 100644 --- a/src/osgManipulator/Projector.cpp +++ b/src/osgManipulator/Projector.cpp @@ -560,7 +560,7 @@ CylinderPlaneProjector::CylinderPlaneProjector() { } -CylinderPlaneProjector::CylinderPlaneProjector(osg::Cylinder* cylinder) : CylinderProjector(cylinder) +CylinderPlaneProjector::CylinderPlaneProjector(osg::Cylinder* cylinder) : CylinderProjector(cylinder), _parallelPlane(false) { } @@ -597,7 +597,7 @@ bool CylinderPlaneProjector::project(const PointerInfo& pi, osg::Vec3d& projecte return true; } -osg::Quat CylinderPlaneProjector::getRotation(const osg::Vec3d& p1, bool p1OnCyl, const osg::Vec3d& p2, bool p2OnCyl) const +osg::Quat CylinderPlaneProjector::getRotation(const osg::Vec3d& p1, const osg::Vec3d& p2) const { if(_parallelPlane) { diff --git a/src/osgManipulator/RotateCylinderDragger.cpp b/src/osgManipulator/RotateCylinderDragger.cpp index 196bec7e3..cbe75602d 100644 --- a/src/osgManipulator/RotateCylinderDragger.cpp +++ b/src/osgManipulator/RotateCylinderDragger.cpp @@ -22,6 +22,49 @@ using namespace osgManipulator; +namespace +{ + +//------------------------------------------------------------------------------ +osg::Geometry* createDiskGeometry(float radius, float offset, float z, unsigned int numSegments + ) +{ + const float angleDelta = 2.0f*osg::PI/float(numSegments); + const unsigned int numPoints = (numSegments+1) * 2; + float angle = 0.0f; + osg::Vec3Array* vertexArray = new osg::Vec3Array(numPoints); + osg::Vec3Array* normalArray = new osg::Vec3Array(numPoints); + unsigned int p = 0; + for(unsigned int i = 0; i < numSegments; ++i,angle+=angleDelta) + { + float c = cosf(angle); + float s = sinf(angle); + // Outer point + (*vertexArray)[p].set(radius*c, radius*s, z); + (*normalArray)[p].set(0.0, 0.0, -1.0); + ++p; + // Inner point + (*vertexArray)[p].set((radius-offset)*c, (radius-offset)*s, z); + (*normalArray)[p].set(0.0, 0.0, -1.0); + ++p; + } + // do last points by hand to ensure no round off errors. + (*vertexArray)[p] = (*vertexArray)[0]; + (*normalArray)[p] = (*normalArray)[0]; + ++p; + (*vertexArray)[p] = (*vertexArray)[1]; + (*normalArray)[p] = (*normalArray)[1]; + + osg::Geometry* geometry = new osg::Geometry; + geometry->setVertexArray(vertexArray); + geometry->setNormalArray(normalArray); + geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size())); + return geometry; +} + +} + RotateCylinderDragger::RotateCylinderDragger() { _projector = new CylinderPlaneProjector(); @@ -73,7 +116,6 @@ bool RotateCylinderDragger::handle(const PointerInfo& pointer, const osgGA::GUIE _prevWorldProjPt = projectedPoint * _projector->getLocalToWorld(); _prevRotation = osg::Quat(); - _prevPtOnCylinder = _projector->isProjectionOnCylinder(); aa.requestRedraw(); } @@ -91,8 +133,8 @@ bool RotateCylinderDragger::handle(const PointerInfo& pointer, const osgGA::GUIE if (_projector->project(pointer, projectedPoint)) { osg::Vec3d prevProjectedPoint = _prevWorldProjPt * _projector->getWorldToLocal(); - osg::Quat deltaRotation = _projector->getRotation(prevProjectedPoint, _prevPtOnCylinder, - projectedPoint, _projector->isProjectionOnCylinder()); + osg::Quat deltaRotation = _projector->getRotation(prevProjectedPoint, + projectedPoint); osg::Quat rotation = deltaRotation * _prevRotation; // Generate the motion command. @@ -106,7 +148,6 @@ bool RotateCylinderDragger::handle(const PointerInfo& pointer, const osgGA::GUIE _prevWorldProjPt = projectedPoint * _projector->getLocalToWorld(); _prevRotation = rotation; - _prevPtOnCylinder = _projector->isProjectionOnCylinder(); aa.requestRedraw(); } return true; @@ -138,6 +179,34 @@ bool RotateCylinderDragger::handle(const PointerInfo& pointer, const osgGA::GUIE void RotateCylinderDragger::setupDefaultGeometry() { osg::Geode* geode = new osg::Geode; - geode->addDrawable(new osg::ShapeDrawable(const_cast(_projector->getCylinder()))); + { + osg::TessellationHints* hints = new osg::TessellationHints; + hints->setCreateTop(false); + hints->setCreateBottom(false); + hints->setCreateBackFace(false); + + float radius = 1.0f; + float height = 0.1f; + float thickness = 0.1f; + + // outer cylinder + osg::Cylinder* cylinder = new osg::Cylinder; + cylinder->setHeight(height); + cylinder->setRadius(radius); + osg::ShapeDrawable* cylinderDrawable = new osg::ShapeDrawable(cylinder, hints); + geode->addDrawable(cylinderDrawable); + + // inner cylinder + osg::Cylinder* cylinder1 = const_cast(_projector->getCylinder()); + cylinder1->setHeight(height); + cylinder1->setRadius(radius-thickness); + osg::ShapeDrawable* cylinderDrawable1 = new osg::ShapeDrawable(cylinder1, hints); + geode->addDrawable(cylinderDrawable1); + + // top + geode->addDrawable(createDiskGeometry(radius, thickness, height/2, 100)); + // bottom + geode->addDrawable(createDiskGeometry(radius, thickness, -height/2, 100)); + } addChild(geode); }