/*----------------------------------------------------------------------------* | sourcefile Line3D.cpp | | | | version 1.00 | | | | | | This file is part of the 3D Geometry Primer, found at: | | http://www.flipcode.com/geometry/ | | | | It contains an example implementation of a 3D line. | | You can find more info in the 3D Geometry Primer on www.flipcode.com. | | | | | | Copyright (C) 2002 Bram de Greve | | | | This library is free software; you can redistribute it and/or | | modify it under the terms of the GNU Lesser General Public | | License as published by the Free Software Foundation; either | | version 2.1 of the License, or (at your option) any later version. | | | | 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 GNU | | Lesser General Public License for more details. | | | | You should have received a copy of the GNU Lesser General Public | | License along with this library; if not, write to the Free Software | | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | | | | You can contact me by e-mail on bdegreve@mail.be | *----------------------------------------------------------------------------*/ #include "Line3D.h" // ----------------------------------------------------------------------------- // DEFAULT CONSTRUCTOR // // this constructor will create a line with the origin as support point and // a direction vector that'll point along the positive z-axis. // i.e. this line will lie along the z-axis. // ----------------------------------------------------------------------------- Line3D::Line3D(): m_support(0.0f, 0.0f, 0.0f), m_direction(0.0f, 0.0f, 1.0f) { } // ----------------------------------------------------------------------------- // CONSTRUCTOR point vector // // this conststruct will create a line with a given support point and // direction vector. the direction vector will be normalized // ----------------------------------------------------------------------------- Line3D::Line3D(const Point3D& a_support, const Vector3D& a_direction): m_support(a_support), m_direction(a_direction) { m_direction.normalize(); } // ----------------------------------------------------------------------------- // CONSTRUCTOR point point // // this constructor will create a line through both points. First point // will serve as support point and the direction vector will point from // the support point to the second point. the direction vector will // be normalized // ----------------------------------------------------------------------------- Line3D::Line3D(const Point3D& a_support, const Point3D& a_secondPoint): m_support(a_support), m_direction(a_secondPoint - a_support) { m_direction.normalize(); } // ----------------------------------------------------------------------------- // SET point vector // // this accessor will set this line to have a given support point and // direction vector. the direction vector will be normalized // ----------------------------------------------------------------------------- void Line3D::set(const Point3D& a_support, const Vector3D& a_direction) { m_support = a_support; m_direction = a_direction; m_direction.normalize(); } // ----------------------------------------------------------------------------- // SET point point // // this accessor will set this line to go through two given points. the first // one will serve as support point and the direction vector will point from // this support point to the second point. the direction vector will be // normalized // ----------------------------------------------------------------------------- void Line3D::set(const Point3D& a_support, const Point3D& a_secondPoint) { m_support = a_support; m_direction = a_secondPoint - a_support; m_direction.normalize(); } // ----------------------------------------------------------------------------- // PROJECT point // // return the orthogonal projection of a point onto this line // ----------------------------------------------------------------------------- Point3D Line3D::project(const Point3D& a_point) { const Vector3D sp = a_point - m_support; const float t = dot(sp, m_direction); return getPoint(t); } // ----------------------------------------------------------------------------- // CONTAINS point, tolerance // // return true if point is point of line // ----------------------------------------------------------------------------- bool Line3D::contains(const Point3D& a_point, float a_tolerance) { return dist(*this, a_point) <= a_tolerance; } // ----------------------------------------------------------------------------- // DIST line point // // this method will calculate the (absolute) distance from a point to a line // ----------------------------------------------------------------------------- float dist(const Line3D& a_line, const Point3D& a_point) { const Vector3D sp = a_point - a_line.getSupport(); const float t = dot(sp, a_line.getDirection()); const Vector3D v = sp - t * a_line.getDirection(); return v.getNorm(); } // ----------------------------------------------------------------------------- // DIST line line // // this method will calculate the (absolute) distance between two lines // ----------------------------------------------------------------------------- float dist(const Line3D& a_line1, const Line3D& a_line2) { const Vector3D sr = a_line2.getSupport() - a_line1.getSupport(); const Vector3D d = a_line1.getDirection(); const Vector3D e = a_line2.getDirection(); const Vector3D n = cross(d, e); if (n.isNull()) { const Vector3D v = sr - dot(sr, d) * d; return v.getNorm(); } else { return fabsf(dot(sr, n)); } } // ----------------------------------------------------------------------------- // INTERSECT line line // // this method will calculate the intersection between two lines // // takes: const Line3D& line1 // const Line3D& line2 // float& t1: will return parameter of intersection point on line1 // float& t2: will return parameter of intersection point on line2 // returns: 0: no intersection points found (crossing or parallel lines) // 1: exactly one intersection point found (intersection lines) // -1: a infinite number of intersection points (coincident lines) // ----------------------------------------------------------------------------- int intersect(const Line3D& a_line1, const Line3D& a_line2, float& a_t1, float& a_t2) { const Vector3D sr = a_line2.getSupport() - a_line1.getSupport(); const Vector3D d = a_line1.getDirection(); const Vector3D e = a_line2.getDirection(); const Vector3D n = cross(d, e); // only return intersection points if distance between lines is not null // hardcode distance between lines to reuse normalvector if (n.isNull()) { const Vector3D v = sr - dot(sr, d) * d; if (v.isNull()) { // coincident lines, infinite many intersection points return -1; } else { // parallel lines, no intersection points return 0; } } else { if (dot(sr, n) == 0.0f) { // crossing lines, no intersection points return 0; } } // now we're sure we have exactly one intersection point // use Cramer to find it if (fabsf(n.z) > fabsf(n.x) && fabsf(n.z) > fabsf(n.y)) { const float invNz = 1.0f / n.z; a_t1 = (sr.x * e.y - sr.y * e.x) * invNz; a_t2 = (sr.x * d.y - sr.y * d.x) * invNz; } else if (fabsf(n.x) > fabsf(n.y)) { const float invNx = 1.0f / n.x; a_t1 = (sr.y * e.z - sr.z * e.y) * invNx; a_t2 = (sr.y * d.z - sr.z * d.y) * invNx; } else { const float invNy = 1.0f / n.y; a_t1 = (sr.z * e.x - sr.x * e.z) * invNy; a_t2 = (sr.z * d.x - sr.x * d.z) * invNy; } return 1; } // --- END OF FILE Line3D.cpp --------------------------------------------------