diff --git a/src/Mod/Mesh/App/Core/Elements.cpp b/src/Mod/Mesh/App/Core/Elements.cpp index 57781133d6..2422d45cf8 100644 --- a/src/Mod/Mesh/App/Core/Elements.cpp +++ b/src/Mod/Mesh/App/Core/Elements.cpp @@ -225,6 +225,100 @@ bool MeshGeomEdge::IntersectBoundingBox (const Base::BoundBox3f &rclBB) const return intrsectbox.Test(); } +bool MeshGeomEdge::IntersectWithLine (const Base::Vector3f &rclPt, + const Base::Vector3f &rclDir, + Base::Vector3f &rclRes) const +{ + const float eps = 1e-06f; + Base::Vector3f n = _aclPoints[1] - _aclPoints[0]; + + // check angle between edge and the line direction, FLOAT_MAX is + // returned for degenerated edges + float fAngle = rclDir.GetAngle(n); + if (fAngle == 0) { + // parallel lines + float distance = _aclPoints[0].DistanceToLine(rclPt, rclDir); + if (distance < eps) { + // lines are equal + rclRes = _aclPoints[0]; + return true; + } + + return false; // no intersection possible + } + + // that's the normal of a helper plane and its base at _aclPoints + Base::Vector3f normal = n.Cross(rclDir); + + // if the distance of rclPt to the plane is higher than eps then the + // two lines are warped and there is no intersection possible + if (fabs(rclPt.DistanceToPlane(_aclPoints[0], normal)) > eps) + return false; + + // get a second helper plane and get the intersection with the line + Base::Vector3f normal2 = normal.Cross(n); + + float s = ((_aclPoints[0] - rclPt) * normal2) / (rclDir * normal2); + rclRes = rclPt + s * rclDir; + + float dist1 = Base::Distance(_aclPoints[0], _aclPoints[1]); + float dist2 = Base::Distance(_aclPoints[0], rclRes); + float dist3 = Base::Distance(_aclPoints[1], rclRes); + + return dist2 + dist3 <= dist1 + eps; +} + +void MeshGeomEdge::ProjectPointToLine (const Base::Vector3f &rclPoint, + Base::Vector3f &rclProj) const +{ + Base::Vector3f pt1 = rclPoint - _aclPoints[0]; + Base::Vector3f dir = _aclPoints[1] - _aclPoints[0]; + Base::Vector3f vec; + vec.ProjectToLine(pt1, dir); + rclProj = rclPoint + vec; +} + +void MeshGeomEdge::ClosestPointsToLine(const Base::Vector3f &linePt, const Base::Vector3f &lineDir, + Base::Vector3f& rclPnt1, Base::Vector3f& rclPnt2) const +{ + const float eps = 1e-06f; + Base::Vector3f edgeDir = _aclPoints[1] - _aclPoints[0]; + + // check angle between edge and the line direction, FLOAT_MAX is + // returned for degenerated edges + float fAngle = lineDir.GetAngle(edgeDir); + if (fAngle == 0) { + // parallel lines + float distance = _aclPoints[0].DistanceToLine(linePt, lineDir); + if (distance < eps) { + // lines are equal + rclPnt1 = _aclPoints[0]; + rclPnt2 = _aclPoints[0]; + } + else { + rclPnt1 = _aclPoints[0]; + MeshGeomEdge edge; + edge._aclPoints[0] = linePt; + edge._aclPoints[1] = linePt + lineDir; + edge.ProjectPointToLine(rclPnt1, rclPnt2); + } + } + else { + // that's the normal of a helper plane + Base::Vector3f normal = edgeDir.Cross(lineDir); + + // get a second helper plane and get the intersection with the line + Base::Vector3f normal2 = normal.Cross(edgeDir); + float s = ((_aclPoints[0] - linePt) * normal2) / (lineDir * normal2); + rclPnt2 = linePt + s * lineDir; + + // get a third helper plane and get the intersection with the line + Base::Vector3f normal3 = normal.Cross(lineDir); + float t = ((linePt - _aclPoints[0]) * normal3) / (edgeDir * normal3); + rclPnt1 = _aclPoints[0] + t * edgeDir; + } +} + // ----------------------------------------------------------------- MeshGeomFacet::MeshGeomFacet (void) diff --git a/src/Mod/Mesh/App/Core/Elements.h b/src/Mod/Mesh/App/Core/Elements.h index 951d63ce30..716fb007a9 100644 --- a/src/Mod/Mesh/App/Core/Elements.h +++ b/src/Mod/Mesh/App/Core/Elements.h @@ -164,6 +164,22 @@ public: Base::BoundBox3f GetBoundBox () const; /** Checks if the edge intersects with the given bounding box. */ bool IntersectBoundingBox (const Base::BoundBox3f &rclBB) const; + /** Calculates the intersection point of the line defined by the base \a rclPt and the direction \a rclDir + * with the edge. The intersection must be inside the edge. If there is no intersection false is returned. + */ + bool IntersectWithLine (const Base::Vector3f &rclPt, const Base::Vector3f &rclDir, Base::Vector3f &rclRes) const; + /** + * Calculates the projection of a point onto the line defined by the edge. The caller must check if + * the projection point is inside the edge. + */ + void ProjectPointToLine (const Base::Vector3f &rclPoint, Base::Vector3f &rclProj) const; + /** + * Get the closest points \a rclPnt1 and \a rclPnt2 of the line defined by this edge and the line + * defined by \a rclPt and \a rclDir. + * If the two points are identical then both lines intersect each other. + */ + void ClosestPointsToLine(const Base::Vector3f &linePt, const Base::Vector3f &lineDir, + Base::Vector3f& rclPnt1, Base::Vector3f& rclPnt2) const; public: Base::Vector3f _aclPoints[2]; /**< Corner points */