197 | | osg::Plane computePlaneParallelToAxisAndOrientedToEye(const osg::Vec3d& eyeDir, const osg::Matrix& localToWorld, |
198 | | const osg::Vec3d& axisDir, double radius, |
199 | | osg::Vec3d& planeLineStart, osg::Vec3d& planeLineEnd, |
200 | | bool front) |
201 | | { |
202 | | osg::Vec3d perpDir = axisDir ^ getLocalEyeDirection(eyeDir, localToWorld); |
| 202 | // Computes a plane to be used as a basis for determining a displacement. When eyeDir is close |
| 203 | // to the cylinder axis, then the plane will be set to be perpendicular to the cylinder axis. |
| 204 | // Otherwise it will be set to be parallel to the cylinder axis and oriented towards eyeDir. |
| 205 | osg::Plane computeIntersectionPlane(const osg::Vec3d& eyeDir, const osg::Matrix& localToWorld, |
| 206 | const osg::Vec3d& axisDir, const osg::Cylinder& cylinder, |
| 207 | osg::Vec3d& planeLineStart, osg::Vec3d& planeLineEnd, |
| 208 | bool& parallelPlane, bool front) |
| 209 | { |
| 210 | osg::Plane plane; |
| 211 | |
| 212 | osg::Vec3d unitAxisDir = axisDir; |
| 213 | unitAxisDir.normalize(); |
| 214 | osg::Vec3d perpDir = unitAxisDir ^ getLocalEyeDirection(eyeDir, localToWorld); |
| 215 | |
| 216 | // Check to make sure eye and cylinder axis are not too close |
| 217 | if(perpDir.length2() < CROSS_PRODUCT_ANGLE_TOLERANCE) |
| 218 | { |
| 219 | // Too close, so instead return plane perpendicular to cylinder axis. |
| 220 | plane.set(unitAxisDir, cylinder.getCenter()); |
| 221 | parallelPlane = false; |
| 222 | return plane; |
| 223 | } |
| 224 | |
| 225 | // Otherwise compute plane along axisDir oriented towards eye |
566 | | // Find the intersection of the sphere with the line. |
567 | | osg::Vec3d cylIntersection; |
568 | | bool hitCylinder = false; |
569 | | if (_front) |
570 | | { |
571 | | osg::Vec3d dontCare; |
572 | | hitCylinder = getCylinderLineIntersection(*_cylinder, objectNearPoint, objectFarPoint, cylIntersection, dontCare); |
573 | | } |
574 | | else |
575 | | { |
576 | | osg::Vec3d dontCare; |
577 | | hitCylinder = getCylinderLineIntersection(*_cylinder, objectNearPoint, objectFarPoint, dontCare, cylIntersection); |
578 | | } |
579 | | |
580 | | // Compute plane oriented to the eye. |
581 | | _plane = computePlaneParallelToAxisAndOrientedToEye(pi.getEyeDir(), getLocalToWorld(), _cylinderAxis, |
582 | | getCylinder()->getRadius(), _planeLineStart, _planeLineEnd, |
583 | | _front); |
584 | | |
585 | | // Find the intersection on the plane. |
586 | | osg::Vec3d planeIntersection; |
587 | | getPlaneLineIntersection(_plane.asVec4(), objectNearPoint, objectFarPoint, planeIntersection); |
588 | | |
589 | | if (hitCylinder) |
590 | | { |
591 | | osg::Vec3d projectIntersection; |
592 | | getPlaneLineIntersection(_plane.asVec4(), cylIntersection, cylIntersection + _plane.getNormal(), projectIntersection); |
593 | | |
594 | | osg::Vec3d closestPointToCylAxis; |
595 | | computeClosestPointOnLine(getCylinder()->getCenter(), getCylinder()->getCenter() + _cylinderAxis, |
596 | | projectIntersection, closestPointToCylAxis); |
597 | | |
598 | | // Distance from the plane intersection point to the closest point on the cylinder axis. |
599 | | double dist = (projectIntersection - closestPointToCylAxis).length(); |
600 | | |
601 | | if (dist < getCylinder()->getRadius()) |
602 | | { |
603 | | if (!hitCylinder) return false; |
604 | | projectedPoint = cylIntersection; |
605 | | _onCylinder = true; |
606 | | } |
607 | | else |
608 | | { |
609 | | projectedPoint = planeIntersection; |
610 | | _onCylinder = false; |
611 | | } |
612 | | } |
613 | | else |
614 | | { |
615 | | projectedPoint = planeIntersection; |
616 | | _onCylinder = false; |
617 | | } |
618 | | |
| 589 | // Computes either a plane parallel to cylinder axis oriented to the eye or the plane |
| 590 | // perpendicular to the cylinder axis if the eye-cylinder angle is close. |
| 591 | _plane = computeIntersectionPlane(pi.getEyeDir(), getLocalToWorld(), _cylinderAxis, |
| 592 | *_cylinder, _planeLineStart, _planeLineEnd, |
| 593 | _parallelPlane, _front); |
| 594 | |
| 595 | // Now find the point of intersection on our newly-calculated plane. |
| 596 | getPlaneLineIntersection(_plane.asVec4(), objectNearPoint, objectFarPoint, projectedPoint); |
624 | | if (p1OnCyl && p2OnCyl) |
625 | | { |
626 | | osg::Vec3d closestPointToCylAxis1, closestPointToCylAxis2; |
627 | | computeClosestPointOnLine(getCylinder()->getCenter(), getCylinder()->getCenter() + _cylinderAxis * getCylinder()->getHeight(), |
628 | | p1, closestPointToCylAxis1); |
629 | | computeClosestPointOnLine(getCylinder()->getCenter(), getCylinder()->getCenter() + _cylinderAxis * getCylinder()->getHeight(), |
630 | | p2, closestPointToCylAxis2); |
631 | | |
632 | | osg::Vec3d v1 = p1 - closestPointToCylAxis1; |
633 | | osg::Vec3d v2 = p2 - closestPointToCylAxis2; |
634 | | |
635 | | double cosAngle = v1 * v2 / (v1.length() * v2.length()); |
636 | | |
637 | | if (cosAngle > 1.0 || cosAngle < -1.0) |
638 | | return osg::Quat(); |
639 | | |
640 | | double angle = acosf(cosAngle); |
641 | | osg::Vec3d rotAxis = v1 ^ v2; |
642 | | |
643 | | return osg::Quat(angle, rotAxis); |
644 | | } |
645 | | else if (!p1OnCyl && !p2OnCyl) |
| 602 | if(_parallelPlane) |
670 | | osg::Vec3d offCylinderPt = (p1OnCyl) ? p2 : p1; |
671 | | |
672 | | osg::Vec3d linePtNearest; |
673 | | computeClosestPointOnLine(_planeLineStart, _planeLineEnd, |
674 | | offCylinderPt, linePtNearest); |
675 | | osg::Vec3d dirToOffCylinderPt = offCylinderPt - linePtNearest; |
676 | | dirToOffCylinderPt.normalize(); |
677 | | |
678 | | osg::Vec3d ptOnCylinder = linePtNearest + dirToOffCylinderPt * getCylinder()->getRadius(); |
679 | | |
680 | | if (p1OnCyl) |
681 | | return (getRotation(p1, true, ptOnCylinder, true) * |
682 | | getRotation(ptOnCylinder, false, p2, false)); |
683 | | else |
684 | | return (getRotation(p1, false, ptOnCylinder, false) * |
685 | | getRotation(ptOnCylinder, true, p2, true)); |
686 | | } |
687 | | } |
| 627 | osg::Vec3d v1 = p1 - getCylinder()->getCenter(); |
| 628 | osg::Vec3d v2 = p2 - getCylinder()->getCenter(); |
| 629 | |
| 630 | double cosAngle = v1 * v2 / (v1.length() * v2.length()); |
| 631 | |
| 632 | if (cosAngle > 1.0 || cosAngle < -1.0) |
| 633 | return osg::Quat(); |
| 634 | |
| 635 | double angle = acosf(cosAngle); |
| 636 | osg::Vec3d rotAxis = v1 ^ v2; |
| 637 | |
| 638 | return osg::Quat(angle, rotAxis); |
| 639 | } |
| 640 | } |