| 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 | } |