/**************************************************************************\ * * This file is part of the Coin 3D visualization library. * Copyright (C) 1998-2007 by Systems in Motion. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * ("GPL") version 2 as published by the Free Software Foundation. * See the file LICENSE.GPL at the root directory of this source * distribution for additional information about the GNU GPL. * * For using Coin with software that can not be combined with the GNU * GPL, and for taking advantage of the additional benefits of our * support services, please contact Systems in Motion about acquiring * a Coin Professional Edition License. * * See http://www.coin3d.org/ for more information. * * Systems in Motion, Postboks 1283, Pirsenteret, 7462 Trondheim, NORWAY. * http://www.sim.no/ sales@sim.no coin-support@coin3d.org * \**************************************************************************/ /*! \class SbCylinderPlaneProjector SbCylinderPlaneProjector.h Inventor/projectors/SbCylinderPlaneProjector.h \brief The SbCylinderPlaneProjector class projects 2D points to a half-cylinder and a plane. \ingroup projectors This projector uses a plane along with the half-cylinder of SbCylinderSectionProjector for projections. If the 2D point mapping "misses" the cylinder section, the 3D point will be projected onto the plane. \sa SbSpherePlaneProjector */ #include #if COIN_DEBUG #include #endif // COIN_DEBUG #include /*! Default constructor. See SbCylinderSectionProjector::SbCylinderSectionProjector(). */ SbCylinderPlaneProjector::SbCylinderPlaneProjector(const float edgetol, const SbBool orienttoeye) : SbCylinderSectionProjector(edgetol, orienttoeye) { } /*! Constructor with explicit specification of projection cylinder. */ SbCylinderPlaneProjector::SbCylinderPlaneProjector(const SbCylinder & cyl, const float edgetol, const SbBool orienttoeye) : SbCylinderSectionProjector(cyl, edgetol, orienttoeye) { } // Documented in superclass. SbProjector * SbCylinderPlaneProjector::copy(void) const { return new SbCylinderPlaneProjector(*this); } // Documented in superclass. SbVec3f SbCylinderPlaneProjector::project(const SbVec2f & point) { if (this->needSetup) this->setupTolerance(); SbLine projline = this->getWorkingLine(point); SbVec3f projpt; SbBool tst = this->intersectCylinderFront(projline, projpt); if (!tst || !this->isWithinTolerance(projpt)) { if (!this->tolPlane.intersect(projline, projpt)) { #if COIN_DEBUG SoDebugError::postWarning("SbCylinderSectionProjector::project", "working line is parallel to cylinder axis."); #endif // COIN_DEBUG return SbVec3f(0.0f, 0.0f, 0.0f); } } this->lastPoint = projpt; return projpt; } // Documented in superclass. SbRotation SbCylinderPlaneProjector::getRotation(const SbVec3f & point1, const SbVec3f & point2) { SbBool tol1 = this->isWithinTolerance(point1); SbBool tol2 = this->isWithinTolerance(point2); return this->getRotation(point1, tol1, point2, tol2); } /*! Calculates rotation from \a point1 to \a point2, with \a tol1 and \a tol2 deciding whether or not to use the tolerance setting. */ SbRotation SbCylinderPlaneProjector::getRotation(const SbVec3f & point1, const SbBool tol1, const SbVec3f & point2, const SbBool tol2) { if (tol1 && tol2) return inherited::getRotation(point1, point2); if (point1 == point2) { return SbRotation(this->cylinder.getAxis().getDirection(), 0.0f); } // create a line to project projections onto. This will make // the below calculations much simpler. SbLine horizline; SbVec3f dir = this->cylinder.getAxis().getDirection().cross(this->planeDir); horizline = SbLine(this->planeLine.getPosition(), this->planeLine.getPosition() + dir); // // pt1 is the point projected onto horizline. pt1_tol is different from // pt1 if tol1==FALSE. pt1_tol will then be on the edge of the cylinder // section, where the cylinder section intersects the plane, but it will // also be on horizline. // SbVec3f pt1, pt1_tol, pt2, pt2_tol; pt1 = horizline.getClosestPoint(point1); pt2 = horizline.getClosestPoint(point2); if (tol1) { pt1_tol = pt1; } else { SbVec3f ptOnLine = this->planeLine.getClosestPoint(point1); SbLine myLine(point1, ptOnLine); if (!this->cylinder.intersect(myLine, pt1_tol)) { // shouldn't happen, but be robust if it does return SbRotation(SbVec3f(0.0f, 0.0f, 1.0f), 0.0f); } pt1_tol = horizline.getClosestPoint(pt1_tol); } if (tol2) { pt2_tol = pt2; } else { SbVec3f ptOnLine = this->planeLine.getClosestPoint(point2); SbLine myLine(pt2, ptOnLine); if (!this->cylinder.intersect(myLine, pt2_tol)) { // shouldn't happen, but be robust if it does return SbRotation(SbVec3f(0.0f, 0.0f, 1.0f), 0.0f); } pt2_tol = horizline.getClosestPoint(pt2_tol); } // find normal cylinder-section rotation SbRotation rot = inherited::getRotation(tol1 ? point1 : pt1_tol, tol2 ? point2 : pt2_tol); SbVec3f axis; float angle; rot.getValue(axis, angle); if (axis.dot(this->cylinder.getAxis().getDirection()) < 0.0f) { axis = -axis; angle = 2.0f*float(M_PI) - angle; } float len = 0.0f; // both pts on same side of cylinder ? if (!tol1 && !tol2 && (pt1_tol == pt2_tol)) { if ((pt1-pt2).dot(dir) < 0.0f) { len += (pt1-pt2).length(); } else { len -= (pt1-pt2).length(); } } else { if (!tol1) { if ((pt1_tol-pt1).dot(dir) < 0.0f) { len -= (pt1_tol-pt1).length(); } else { len += (pt1_tol-pt1).length(); } } if (!tol2) { if ((pt2_tol-pt2).dot(dir) < 0.0f) { len += (pt2_tol-pt2).length(); } else { len -= (pt2_tol-pt2).length(); } } } angle += len / this->cylinder.getRadius(); return SbRotation(this->cylinder.getAxis().getDirection(), angle); }