/// <summary> /// Testing intersection between a line segment and a polyhedron and return ALL intersection points /// </summary> /// <param name="polyH">Polyhedron</param> /// <param name="lineS">Line segment</param> /// <param name="intPoints">List of intersection points</param> /// <returns></returns> public static bool intersect(Polyhedron polyH, LineSegment3D lineS, out List <Point3D> intPoints) { List <Point3D> iPoints = new List <Point3D>(); intPoints = iPoints; List <Point3D> corners = new List <Point3D>(); corners.Add(lineS.startPoint); corners.Add(lineS.endPoint); BoundingBox3D bound = new BoundingBox3D(corners); List <Face3D> reducedList = Face3D.exclFacesOutsideOfBound(polyH.Faces, bound, 0x111); if (reducedList.Count == 0) { return(false); // no faces left, either they are all on the left or they are all on the right } // Now test whether there is any intersection. It needs to complete the test with entire faces to collect the intersection points for (int i = 0; i < reducedList.Count; i++) { List <Point3D> iPts = new List <Point3D>(); if (Face3D.intersect(reducedList[i], lineS, out iPts)) { for (int j = 0; j < iPts.Count; j++) { iPoints.Add(iPts[j]); } } } if (iPoints.Count > 0) { return(true); } return(false); }
/// <summary> /// Touch check between 2 faces. Currently only returns true/false. Should be improved with a new face that overlap between the 2 input faces /// </summary> /// <param name="F1">Face 1</param> /// <param name="F2">Face 2</param> /// <returns></returns> public static bool touch(Face3D F1, Face3D F2) { if (Vector3D.Parallels(F1._basePlane.normalVector, F2._basePlane.normalVector)) { // test for any point inside another face for (int i = 0; i < F2._vertices.Count; i++) { if (Face3D.inside(F1, F2._vertices[i])) { return(true); } } for (int i = 0; i < F1._vertices.Count; i++) { if (Face3D.inside(F2, F1._vertices[i])) { return(true); } } // if still not returning true, test whether the edges intersect List <Point3D> intPoints = new List <Point3D>(); for (int i = 0; i < F2.boundaries.Count; ++i) { if (Face3D.intersect(F1, F2.boundaries[i], out intPoints)) { return(true); } } } return(false); }
/// <summary> /// Testing a point inside a polyhedron is similar with the 2D version of a point inside a polygon by testing intersection between a ray starting from the point. /// If the number of intersection is odd the point is inside. In 3D the intersection is against the Faces /// </summary> /// <param name="polyH"></param> /// <param name="aPoint"></param> /// <returns></returns> public static bool inside(Polyhedron polyH, Point3D aPoint) { double extent = 0; if (Octree.WorldBB == null) { extent = Point3D.distance(polyH.boundingBox.LLB, polyH.boundingBox.URT); } else { extent = Octree.WorldBB.extent; } // define a ray using linesegment from the point toward and along +X-axis with 2*the extent of the World BB to ensure ray is always long enough LineSegment3D ray = new LineSegment3D(aPoint, new Point3D(aPoint.X + 2 * extent, aPoint.Y, aPoint.Z)); List <Face3D> reducedList = Face3D.inclFacesBeyondAxis(polyH.Faces, new Plane3D(aPoint, new Vector3D(1.0, 0.0, 0.0))); // beyond YZ plane List <Point3D> corners = new List <Point3D>(); corners.Add(aPoint); corners.Add(aPoint); BoundingBox3D bound = new BoundingBox3D(corners); if (reducedList.Count > 0) { reducedList = Face3D.exclFacesOutsideOfBound(reducedList, bound, 0x011); // reduce list on Y and Z both direction } if (reducedList.Count == 0) { return(false); // no faces left, either they are all on the left or they are all on the right } int iCount = 0; for (int i = 0; i < reducedList.Count; i++) { List <Point3D> intPts = new List <Point3D>(); if (Face3D.intersect(reducedList[i], ray, out intPts)) { iCount++; } } if ((iCount % 2) == 1) { return(true); } return(false); }
/// <summary> /// To determine that a line segment is inside (completely inside) of a polyhedron, it must satisfy the following: /// 1. both end points are inside the polyhedron /// 2. There no intersection between the segment and the polyhedron /// </summary> /// <param name="polyH"></param> /// <param name="lineS"></param> /// <returns></returns> public static bool inside(Polyhedron polyH, LineSegment3D lineS) { // reducing the face candidate list is less expensive than inside test, do it first Point3D leftX = new Point3D(); Point3D rightX = new Point3D(); leftX.X = lineS.startPoint.X < lineS.endPoint.X ? lineS.startPoint.X : lineS.endPoint.X; rightX.X = lineS.startPoint.X < lineS.endPoint.X ? lineS.endPoint.X : lineS.startPoint.X; List <Face3D> reducedList = Face3D.inclFacesBeyondAxis(polyH.Faces, new Plane3D(leftX, new Vector3D(1.0, 0.0, 0.0))); // reducedList = Face3D.exclFacesBeyondAxis(reducedList, rightX); // cannot remove this otherwise inside test for StartPoint may not be correct!!! List <Point3D> corners = new List <Point3D>(); corners.Add(lineS.startPoint); corners.Add(lineS.endPoint); BoundingBox3D bound = new BoundingBox3D(corners); if (reducedList.Count > 0) { reducedList = Face3D.exclFacesOutsideOfBound(reducedList, bound, 0x011); // reduce list on Y and Z both direction } if (reducedList.Count == 0) { return(false); // no faces left, either they are all on the left or they are all on the right } // inside test for both segment ends. Test one by one so that we can exit when any one of them are not inside if (!inside(polyH, lineS.startPoint)) { return(false); } if (!inside(polyH, lineS.endPoint)) { return(false); } // Now test whether there is any intersection. If there is, the segment is not completely inside for (int i = 0; i < reducedList.Count; i++) { List <Point3D> iPoints = new List <Point3D>(); if (Face3D.intersect(reducedList[i], lineS, out iPoints)) { return(false); } } return(true); }
/// <summary> /// Test whether a Face (bounded plane) intersects with a plane /// </summary> /// <param name="P1">Plane</param> /// <param name="F1">Face</param> /// <param name="intersectingLine">Resulting intercting linesegment (bounded)</param> /// <returns></returns> public static bool PPintersect(Plane3D P1, Face3D F1, out LineSegment3D intersectingLine) { Line3D intLine = new Line3D(); LineSegment3D ls = new LineSegment3D(new Point3D(0.0, 0.0, 0.0), new Point3D(1.0, 1.0, 1.0)); intersectingLine = ls; // Intersect operation: get the intersection (unbounded) line if (!PPintersect(P1, F1.basePlane, out intLine)) { return(false); } // Now needs to check get the segment by getting intersecting points between the line and the Face boundaries List <Point3D> intPts = new List <Point3D>(); // Use line segment that is large enough to ensure it covers the extent of the face //double extent = Point3D.distance(F1.boundingBox.LLB, F1.boundingBox.URT) * 10; // Bug: NOT big enough for some cases!, use worldBB extent double extent; if (Octree.WorldBB == null) { extent = 1000000000; } else { extent = Octree.WorldBB.extent * 10; } LineSegment3D intLS = new LineSegment3D(new Point3D(intLine.point - (intLine.direction * extent)), new Point3D(intLine.point + (intLine.direction * extent))); bool res = Face3D.intersect(F1, intLS, out intPts); if (res) { intersectingLine.startPoint = intPts[0]; intersectingLine.endPoint = intPts[intPts.Count - 1]; return(true); } return(false); }
/// <summary> /// Test intersection between a polyhedron and a face. There is optmization applied for axis-aligned face (useful for Octree cells as they are all axis aligned) /// </summary> /// <param name="polyH">The Polyhedron</param> /// <param name="face">The face to test the intersection</param> /// <returns>true=intersected; false otherwise</returns> public static bool intersect(Polyhedron polyH, Face3D face) { List <Face3D> faceList = new List <Face3D>(); BoundingBox3D bound = new BoundingBox3D(face.vertices); faceList = Face3D.exclFacesOutsideOfBound(polyH.Faces, bound, 0x111); if (faceList.Count == 0) { return(false); // There is no face remaining to test, return false } for (int i = 0; i < faceList.Count; i++) { FaceIntersectEnum mode; LineSegment3D intL = new LineSegment3D(new Point3D(), new Point3D()); bool status = Face3D.intersect(face, faceList[i], out intL, out mode); if (status == true) { return(true); // return true as soon as an intersection is detected } } return(false); }
/// <summary> /// Testing intersection between a line segment and a polyhedron only. It stops at the first intersection /// </summary> /// <param name="polyH">polyhedron</param> /// <param name="lineS">Line segment</param> /// <returns></returns> public static bool intersect(Polyhedron polyH, LineSegment3D lineS) { List <Point3D> corners = new List <Point3D>(); corners.Add(lineS.startPoint); corners.Add(lineS.endPoint); BoundingBox3D bound = new BoundingBox3D(corners); List <Face3D> reducedList = Face3D.exclFacesOutsideOfBound(polyH.Faces, bound, 0x111); if (reducedList.Count == 0) { return(false); // no faces left, either they are all on the left or they are all on the right } // Now test whether there is any intersection. for (int i = 0; i < reducedList.Count; i++) { List <Point3D> iPoints = new List <Point3D>(); if (Face3D.intersect(reducedList[i], lineS, out iPoints)) { return(true); } } return(false); }