/// <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> /// Test a linesegment is completely inside a bounded face. For it to be true, it must fulfill: /// 1. Both endpoints are inside the face /// 2. the segment does not intersect the face /// </summary> /// <param name="F1">The Face</param> /// <param name="LS">The Line Segment</param> /// <returns>true=inside; otherwise false</returns> public static bool inside(Face3D F1, LineSegment3D LS) { // Line segment must completely lie on the face LineSegment3D lineS1 = new LineSegment3D(F1.basePlane.point, LS.startPoint); LineSegment3D lineS2 = new LineSegment3D(F1.basePlane.point, LS.endPoint); double d1 = Vector3D.DotProduct(F1.basePlane.normalVector, lineS1.baseLine.direction); double d2 = Vector3D.DotProduct(F1.basePlane.normalVector, lineS2.baseLine.direction); if (!MathUtils.equalTol(d1, 0.0, MathUtils.defaultTol) || !MathUtils.equalTol(d2, 0.0, MathUtils.defaultTol)) { return(false); // The segment does not lie on the face/plane } // To optimize the algorithm a little bit, we will change the way we test: // First we do intersection test between the face and the linesegment // Second we test at least one point must be inside the face List <Point3D> iPoints = new List <Point3D>(); bool ret = intersect(F1, LS, out iPoints); if (ret) { return(false); // The segment intersect the face } // Test whether at least one point is inside the face ret = inside(F1, LS.startPoint); if (ret) { return(true); } return(false); }
/// <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); }
public static bool isNullFace(Face3D theFace) { Point3D firstP = null; bool first = true; bool nullFace = false; foreach (Point3D p in theFace.vertices) { if (first) { firstP = p; first = false; } else { if (p == firstP) { nullFace = true; } else { return(false); } } } return(nullFace); }
/// <summary> /// A static function to offset a face. It basically shifts the entire face according to the supplies vector value /// </summary> /// <param name="theFace">the Face to be shifted</param> /// <param name="offsetVector">the vector value to shift the Face</param> /// <returns>the new Face</returns> public static Face3D offsetFace(Face3D theFace, Vector3D offsetVector) { List <List <Point3D> > newFaceVerts = new List <List <Point3D> >(); List <Point3D> newOuterVerts = new List <Point3D>(); foreach (Point3D p in theFace.verticesWithHoles[0]) { Point3D newP = new Point3D(); newP = p + offsetVector; newOuterVerts.Add(newP); } newFaceVerts.Add(newOuterVerts); for (int i = 1; i < theFace.verticesWithHoles.Count; ++i) { List <Point3D> newInnerVerts = new List <Point3D>(); foreach (Point3D p in theFace.verticesWithHoles[i]) { Point3D newP = new Point3D(); newP = p + offsetVector; newInnerVerts.Add(newP); } newFaceVerts.Add(newInnerVerts); } Face3D newFace = new Face3D(newFaceVerts); return(newFace); }
public static bool Overlaps(Plane3D P1, Face3D F1) { bool parallel = Vector3D.Parallels(P1.normalVector, F1.basePlane.normalVector); bool pOnPlane = pointOnPlane(P1, F1.vertices[0]); // if the normals are the same and point in P2 is also point in P1, the two planes are overlapped return(parallel && pOnPlane); }
public Face3DLW(Face3D f3d) { vertices = new List <Point3DLW>(); foreach (Point3D p in f3d.vertices) { vertices.Add(new Point3DLW(p)); } }
public static bool validateFace(Face3D face) { if (double.IsNaN(face.basePlane.normalVector.X) || double.IsNaN(face.basePlane.normalVector.Y) || double.IsNaN(face.basePlane.normalVector.Z) || (face.basePlane.normalVector.X == 0.0 && face.basePlane.normalVector.Y == 0.0 && face.basePlane.normalVector.Z == 0.0)) { return(false); } return(true); }
/// <summary> /// To determin a face is inside a polyhedron, all the segments must be completely inside the polyhedron (fulfills the inside test for linesegment) /// </summary> /// <param name="polyH"></param> /// <param name="face"></param> /// <returns></returns> public static bool inside(Polyhedron polyH, Face3D face) { for (int i = 0; i < face.boundaries.Count; i++) { if (!inside(polyH, face.boundaries[i])) { return(false); } } return(true); }
/// <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> /// Calculating an intersection between a Face and a LineSegment /// </summary> /// <param name="F1">the Face3D</param> /// <param name="LS">the Line Segment</param> /// <param name="intPoint">the intersection point</param> /// <returns></returns> public static bool intersect(Face3D F1, LineSegment3D LS, out List <Point3D> intPoints) { intPoints = new List <Point3D>(); Point3D intPt = new Point3D(); // There are 2 possible cases: 1. Line punching the face, 2. Line lies on the same plane as the face // Test whether the line is on the same plane if (MathUtils.equalTol(Vector3D.DotProduct(F1.basePlane.normalVector, LS.baseLine.direction), 0.0, MathUtils.defaultTol)) { // test whether at least one point of the segment is on the plane if (!Plane3D.pointOnPlane(F1.basePlane, LS.startPoint)) { return(false); // line is parallel with the plane, no intersection } LineSegmentIntersectEnum mode = LineSegmentIntersectEnum.Undefined; for (int i = 0; i < F1.boundaries.Count; i++) { bool st = LineSegment3D.intersect(F1.boundaries[i], LS, out intPt, out mode); if (st) { intPoints.Add(intPt); } } if (intPoints.Count > 0) { return(true); } return(false); } else { bool res = Plane3D.PLintersect(F1.basePlane, LS, out intPt); if (res == false) { return(false); // intersection occurs beyond the line segment } // There is intersection point, test whether the point in within (inside the boundary of the face boundaries res = inside(F1, intPt); if (res) { intPoints.Add(intPt); 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> /// Test a face is completely inside another face. For it to be true, it must fulfill: /// 1. All the vertices are inside the other face /// 2. There is no intersection between the edges with the other face /// </summary> /// <param name="F1">The Face</param> /// <param name="F2">The other face to test whether it is inside the first face</param> /// <returns>true=inside, otherwise false</returns> public static bool inside(Face3D F1, Face3D F2) { // Do intersection first for (int i = 0; i < F1.boundaries.Count; i++) { for (int j = 0; j < F2.boundaries.Count; j++) { Point3D iPoint = new Point3D(); LineSegmentIntersectEnum mode; if (LineSegment3D.intersect(F1.boundaries[i], F2.boundaries[j], out iPoint, out mode)) { return(false); // there is intersection } } } // If there is no intersection, at least one vertex of F2 must be inside F1 if (inside(F1, F2.vertices[0])) { return(true); // one vertex of F2 is inside F1 and there is no intersection } return(false); }
/// <summary> /// Compute Octree for a face /// </summary> /// <param name="elementID"></param> /// <param name="face"></param> /// <param name="forUserDict"></param> public void ComputeOctree(string elementID, Face3D face, bool forUserDict) { // Make sure ElementID string is 22 character long for correct encoding/decoding if (elementID.Length < 22) { elementID = elementID.PadLeft(22, '0'); } ElementID eidNo = new ElementID(elementID); Tuple <UInt64, UInt64> elementIDNo = eidNo.ElementIDNo; OctreeNode theTree = new OctreeNode(); // Add a step: // 1. Find the smallest containing cell based on the Face BB, it it to quickly eliminate the irrelevant cells very quickly theTree.nodeCellID = OctreeNodeProcess.getSmallestContainingCell(face); theTree._depth = theTree.nodeCellID.Level; OctreeNodeProcess.Process(theTree, face); List <CellID64> collCellID; List <int> collBorderFlag; OctreeNodeProcess.collectCellIDs(theTree, out collCellID, out collBorderFlag); for (int i = 0; i < collCellID.Count; ++i) { if (forUserDict) { insertDataToUserDict(elementIDNo, collCellID[i], collBorderFlag[i], false); } else { //insertDataToDictDB(elementID, collCellID[i]); insertDataToDict(elementIDNo, collCellID[i]); } } }
/// <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); }
public static CellID64 getSmallestContainingCell(Face3D face) { return(getSmallestContainingCell(face.boundingBox)); }
public bool intersectWith(Face3D F) { return(Polyhedron.intersect(this._polyHRep, F)); }
/// <summary> /// Test a point is inside a face /// </summary> /// <param name="F1"></param> /// <param name="P1"></param> /// <returns></returns> public static bool inside(Face3D F1, Point3D P1) { if (!Plane3D.pointOnPlane(F1.basePlane, P1)) { return(false); // Point is not on a plane } // test Point inside a Face // Need to project the plane to 2D (XY-, YZ-, or XZ- plane). It should work well with convex face (esp. triangles and rectangles we will deal with mostly) double maxDim = Double.MinValue; int DimttoZero = 0; // First test whether the plane is already axis-aligned (in this case we can just remove the appropriate axis) if (MathUtils.equalTol(F1.basePlane.normalVector.Y, 0.0, MathUtils.defaultTol) && MathUtils.equalTol(F1.basePlane.normalVector.Z, 0.0, MathUtils.defaultTol)) { DimttoZero = 0; // Ignore X, project to Y-Z plane } else if (MathUtils.equalTol(F1.basePlane.normalVector.X, 0.0, MathUtils.defaultTol) && MathUtils.equalTol(F1.basePlane.normalVector.Z, 0.0, MathUtils.defaultTol)) { DimttoZero = 1; // Ignore Y, project to X-Z plane } else if (MathUtils.equalTol(F1.basePlane.normalVector.X, 0.0, MathUtils.defaultTol) && MathUtils.equalTol(F1.basePlane.normalVector.Y, 0.0, MathUtils.defaultTol)) { DimttoZero = 2; // Ignore Z, project to X-Y plane } else { if (maxDim < Math.Abs(F1.basePlane.normalVector.X)) { maxDim = Math.Abs(F1.basePlane.normalVector.X); DimttoZero = 0; } if (maxDim < Math.Abs(F1.basePlane.normalVector.Y)) { maxDim = Math.Abs(F1.basePlane.normalVector.Y); DimttoZero = 1; } if (maxDim < Math.Abs(F1.basePlane.normalVector.Z)) { maxDim = Math.Abs(F1.basePlane.normalVector.Z); DimttoZero = 2; } } // We ignore the largest component, which means the least impact to the projection plane List <Point3D> projVert = new List <Point3D>(); Point3D projIntP = new Point3D(P1.X, P1.Y, P1.Z); Point3D rayEndP = new Point3D(P1.X, P1.Y, P1.Z); if (DimttoZero == 0) { for (int i = 0; i < F1.vertices.Count; i++) { projVert.Add(new Point3D(0.0, F1.vertices[i].Y, F1.vertices[i].Z)); } projIntP.X = 0.0; rayEndP.X = 0.0; if (Octree.WorldBB == null) { rayEndP.Y += Point3D.distance(F1.containingBB.URT, F1.containingBB.LLB) * 1000; } else { rayEndP.Y += Octree.WorldBB.extent * 2; } } else if (DimttoZero == 1) { for (int i = 0; i < F1.vertices.Count; i++) { projVert.Add(new Point3D(F1.vertices[i].X, 0.0, F1.vertices[i].Z)); } projIntP.Y = 0.0; rayEndP.Y = 0.0; //rayEndP.Z += Point3D.distance(F1.containingBB.URT, F1.containingBB.LLB) * 2; if (Octree.WorldBB == null) { rayEndP.X += Point3D.distance(F1.containingBB.URT, F1.containingBB.LLB) * 2; // Use X axis for the ray } else { rayEndP.X += Octree.WorldBB.extent * 2; } } else if (DimttoZero == 2) { for (int i = 0; i < F1.vertices.Count; i++) { projVert.Add(new Point3D(F1.vertices[i].X, F1.vertices[i].Y, 0.0)); } projIntP.Z = 0.0; rayEndP.Z = 0.0; if (Octree.WorldBB == null) { rayEndP.X += Point3D.distance(F1.containingBB.URT, F1.containingBB.LLB) * 2; } else { rayEndP.X += Octree.WorldBB.extent * 2; } } Face3D projFace = new Face3D(projVert); // define a ray from the intersection point along the X-axis of the projected plane by using long enough line segment beginning from the point, using // max extent of the face containingBB *2 LineSegment3D ray = new LineSegment3D(projIntP, rayEndP); // Now do intersection between the ray and all the segments of the face. Odd number indicates the point is inside // 4 rules to follow: // 1. If the segment is upward, exclude the endpoint for intersection (only consider the startpoint) // 2. If the segment is downward, exclude the startpoint for intersection (only considers the end point) // 3. Ignore the segment that is horizontal (parallel to the ray) // 4. ray is always strictly to the right of the Point int intCount = 0; Point3D iP = new Point3D(); LineSegmentIntersectEnum mod = LineSegmentIntersectEnum.Undefined; for (int i = 0; i < projFace.boundaries.Count; i++) { if (ray.baseLine.direction == projFace.boundaries[i].baseLine.direction) { continue; //ignore segment that is parallel to the ray (rule #3) } Point3D pointToExclude = new Point3D(); if (DimttoZero == 0 || DimttoZero == 1) { // for both X-Z and Y-Z plane (Z as vertical axis) if (projFace.boundaries[i].startPoint.Z <= ray.startPoint.Z && projFace.boundaries[i].endPoint.Z > ray.startPoint.Z) { pointToExclude = projFace.boundaries[i].endPoint; // Rule #1 } else if (projFace.boundaries[i].startPoint.Z > ray.startPoint.Z && projFace.boundaries[i].endPoint.Z <= ray.startPoint.Z) { pointToExclude = projFace.boundaries[i].startPoint; // Rule #2 } } else { // for X-Y plane (Y as vertical axis) if (projFace.boundaries[i].startPoint.Y <= ray.startPoint.Y && projFace.boundaries[i].endPoint.Y > ray.startPoint.Y) { pointToExclude = projFace.boundaries[i].endPoint; // Rule #1 } else if (projFace.boundaries[i].startPoint.Y > ray.startPoint.Y && projFace.boundaries[i].endPoint.Y <= ray.startPoint.Y) { pointToExclude = projFace.boundaries[i].startPoint; // Rule #2 } } // In the evaluation of the number of intersection between a ray and a face, we will ignore the intersection point that is equal to the rule #2 or #3 if (LineSegment3D.intersect(ray, projFace.boundaries[i], out iP, out mod) && (iP != pointToExclude)) { intCount++; } } if (intCount % 2 == 1) { return(true); } return(false); }
public bool isInside(Face3D F) { return(Polyhedron.inside(this._polyHRep, F)); }
/// <summary> /// Calculating intersection beween 2 Faces. The outcome of the intersection should be a LineSegment /// </summary> /// <param name="F1">First Face</param> /// <param name="F2">Second Face</param> /// <param name="intersectionLine">The resulting intersection line. Zero if no intersection</param> /// <param name="mode">The mode of the intersection: No intersection/parallel, partially intersect, no actual intersection/undefined</param> /// <returns></returns> public static bool intersect(Face3D F1, Face3D F2, out LineSegment3D intersectionLine, out FaceIntersectEnum mode) { intersectionLine = new LineSegment3D(new Point3D(0, 0, 0), new Point3D(0, 0, 0)); mode = FaceIntersectEnum.Undefined; if (F1._basePlane.normalVector == F2._basePlane.normalVector) { // test points inside another face for (int i = 0; i < F2._vertices.Count; i++) { if (!Face3D.inside(F1, F2._vertices[i])) { continue; } mode = FaceIntersectEnum.Overlap; return(true); } mode = FaceIntersectEnum.NoIntersectionParallel; return(false); } LineSegment3D ls1; LineSegment3D ls2; bool res1 = Plane3D.PPintersect(F1._basePlane, F2, out ls1); bool res2 = Plane3D.PPintersect(F2._basePlane, F1, out ls2); if (!res1 || !res2) { return(false); // the faces do not intersect } // Special case if the intersection occurs only at a single point if (ls1.startPoint == ls1.endPoint && ls2.startPoint == ls2.endPoint) { if (ls1.startPoint.Equals(ls2.startPoint)) { mode = FaceIntersectEnum.IntersectPartial; return(true); } return(false); } else if (ls1.startPoint.Equals(ls1.endPoint)) { // a single point intersection: ls1 is 0 length linesegnment = point if (LineSegment3D.isInSegment(ls2, ls1.startPoint)) { mode = FaceIntersectEnum.IntersectPartial; return(true); } return(false); } else if (ls2.startPoint.Equals(ls2.endPoint)) { // a single point intersection: ls1 is 0 length linesegnment = point if (LineSegment3D.isInSegment(ls1, ls2.startPoint)) { mode = FaceIntersectEnum.IntersectPartial; return(true); } return(false); } LineSegment3D ovSegment; LineSegmentOverlapEnum ovstat = LineSegmentOverlapEnum.Undefined; bool lint = LineSegment3D.overlap(ls1, ls2, out ovSegment, out ovstat); if (lint) { intersectionLine = ovSegment; mode = FaceIntersectEnum.IntersectPartial; return(true); } return(false); }
public static void Process(OctreeNode node, Polyhedron _polyH, List <Face3D> polyHF) { // 3rd step. Subdivide the cells collected by the step 2 and operate on them with the actual polyhedron to get the detail if (node._depth < Octree.MaxDepth) { int disjointCount = 0; int insideCount = 0; Split(node); List <int> childToRemove = new List <int>(); List <int> childToTraverse = new List <int>(); List <Face3D> faceList; faceList = Face3D.exclFacesOutsideOfBound(polyHF, node.nodeCellCuboid.cuboidPolyhedron.boundingBox, 0x111); if (faceList.Count == 0) { // No face inside this cuboid left, no intersection nor completely enclosing the polyH. node._flag = PolyhedronIntersectEnum.Disjoint; node._children.Clear(); return; } for (int i = 0; i < node._children.Count; i++) { OctreeNode childNode = node._children[i]; //PolyhedronIntersectEnum intS = childNode.Process(polyH); if (Polyhedron.intersect(childNode.nodeCellCuboid.cuboidPolyhedron, faceList)) { childToTraverse.Add(i); childNode._flag = PolyhedronIntersectEnum.Intersect; childNode.nodeCellID.setBorderCell(); #if (DBG_OCTREE) if (childNode._depth >= _dbgDepth) { BIMRLCommon refCommon = new BIMRLCommon(); string dbgFile = "c:\\temp\\octree\\" + childNode.nodeCellID.ToString() + " - intersect polyH.x3d"; BIMRLExportSDOToX3D x3d = new BIMRLExportSDOToX3D(refCommon, dbgFile); x3d.drawCellInX3d(childNode.nodeCellID.ToString()); // draw the cell x3d.exportFacesToX3D(faceList); x3d.endExportToX3D(); } #endif continue; } // If doesn't intersect (passes the check above), either it is fully contained, full contains or disjoint // To optimize the operation, we will use a single sampling point instead of checking the entire polyhedron since a single point can tell if a polyhedron is inside the other one //if (Polyhedron.inside(childNode.nodeCellCuboid.cuboidPolyhedron, polyH)) //// No need to check this since the previous step (no 1) would have removed the fullycontaining cells // Fully contains check only valid if the parent is fully contains, if intersect, it should never be full contains //if (node._flag == PolyhedronIntersectEnum.FullyContains) //{ // if (Polyhedron.insideCuboid(childNode.nodeCellCuboid.cuboidPolyhedron, faceList[0].vertices[0])) // { // // if polyH is entirely inside the cuboid, we will set this for further split (the same as intersection // childToTraverse.Add(i); // We will remove the node if it is disjoint, otherwise it will continue splitting until the condition met // childNode._flag = PolyhedronIntersectEnum.FullyContains; // childNode.nodeCellID.setBorderCell(); // continue; // } //} //if (Polyhedron.inside(polyH, childNode.nodeCellCuboid.cuboidPolyhedron)) if (Polyhedron.inside(_polyH, childNode.nodeCellCuboid.cuboidPolyhedron.Vertices[3])) { childNode._flag = PolyhedronIntersectEnum.Inside; insideCount++; #if (DBG_OCTREE) if (childNode._depth >= _dbgDepth) { BIMRLCommon refCommon = new BIMRLCommon(); string dbgFile = "c:\\temp\\octree\\" + childNode.nodeCellID.ToString() + " - inside polyH.x3d"; BIMRLExportSDOToX3D x3d = new BIMRLExportSDOToX3D(refCommon, dbgFile); x3d.drawCellInX3d(childNode.nodeCellID.ToString()); // draw the cell x3d.exportFacesToX3D(_polyH.Faces); x3d.endExportToX3D(); } #endif continue; } // If the 2 polyH do not intersect, the cuboid does not fully contain the polyH, nor the cuboid is fully inside the polyH, it must be disjoint childNode._flag = PolyhedronIntersectEnum.Disjoint; disjointCount++; #if (DBG_OCTREE) if (childNode._depth >= _dbgDepth) { BIMRLCommon refCommon = new BIMRLCommon(); string dbgFile = "c:\\temp\\octree\\" + childNode.nodeCellID.ToString() + " - disjoint polyH.x3d"; BIMRLExportSDOToX3D x3d = new BIMRLExportSDOToX3D(refCommon, dbgFile); x3d.drawCellInX3d(childNode.nodeCellID.ToString()); // draw the cell x3d.exportFacesToX3D(_polyH.Faces); x3d.endExportToX3D(); } #endif continue; // else: the cuboid is completely inside the polyH, keep } if (disjointCount == 8) { // All children are disjoint. Remove all children and set the node to Disjoint node._children.Clear(); node._flag = PolyhedronIntersectEnum.Disjoint; return; } if (insideCount == 8) { // All children are inside. Remove all children and set the node to Inside node._children.Clear(); node._flag = PolyhedronIntersectEnum.Inside; return; } if (childToTraverse.Count == 1) { OctreeNodeProcess.Process(node._children[childToTraverse[0]], _polyH, faceList); } else if (childToTraverse.Count > 1) { #if (DEBUG_NOPARALLEL) // Non - parallel option for easier debugging foreach (int i in childToTraverse) { OctreeNodeProcess.Process(node._children[i], _polyH, faceList); } #else ParallelOptions po = new ParallelOptions(); po.MaxDegreeOfParallelism = 8; Parallel.ForEach(childToTraverse, po, i => OctreeNodeProcess.Process(node._children[i], _polyH, faceList)); #endif } // If there is any disjoint, we need to keep this node as it is. This should be done after we processed all the children to be traversed!! if (disjointCount > 0 && disjointCount < 8) { return; } int countGrandChildren = 0; // If there is no disjoint, we need to check whether all children are terminal (i.e. child._children.Count == 0) foreach (OctreeNode child in node._children) { countGrandChildren += child._children.Count; } // All children are terminal and no disjoint (by implication of previous steps). Remove children if (countGrandChildren == 0) { node._children.Clear(); node._flag = PolyhedronIntersectEnum.IntersectOrInside; return; } } else { // at _depth == Octree.MaxDepth there is nothing else to do since the test has been done at the parent level and when entering this stage, the test has determined // that the cell is intersected with the polyH } return; }
/// <summary> /// Process Octree for a face /// </summary> /// <param name="_polyH"></param> /// <param name="polyHF"></param> public static void Process(OctreeNode node, Face3D face) { if (node._depth < Octree.MaxDepth) { int disjointCount = 0; OctreeNodeProcess.Split(node); List <int> childToRemove = new List <int>(); List <int> childToTraverse = new List <int>(); for (int i = 0; i < node._children.Count; i++) { OctreeNode childNode = node._children[i]; if (Polyhedron.intersect(childNode.nodeCellCuboid.cuboidPolyhedron, face)) { childToTraverse.Add(i); childNode._flag = PolyhedronIntersectEnum.Intersect; childNode.nodeCellID.setBorderCell(); continue; } // If doesn't intersect (passes the check above), either it is fully contained, full contains or disjoint // To optimize the operation, we will use a single sampling point instead of checking the entire polyhedron since a single point can tell if a polyhedron is inside the other one // Fully contains check only valid if the parent is fully contains, if intersect, it should never be full contains if (node._flag == PolyhedronIntersectEnum.FullyContains) { if (Polyhedron.insideCuboid(childNode.nodeCellCuboid.cuboidPolyhedron, face.vertices[2])) { // if polyH is entirely inside the cuboid, we will set this for further split (the same as intersection childToTraverse.Add(i); // We will remove the node if it is disjoint, otherwise it will continue splitting until the condition met childNode._flag = PolyhedronIntersectEnum.FullyContains; childNode.nodeCellID.setBorderCell(); continue; } } // If the face does not intersect the cuboid, or the cuboid does not fully contain the polyH, it must be disjoint childNode._flag = PolyhedronIntersectEnum.Disjoint; disjointCount++; continue; } if (disjointCount == 8) { // All children are disjoint. Remove all children and set the node to Disjoint node._children.Clear(); node._flag = PolyhedronIntersectEnum.Disjoint; return; } if (childToTraverse.Count == 1) { OctreeNodeProcess.Process(node._children[childToTraverse[0]], face); } else if (childToTraverse.Count > 1) { Parallel.ForEach(childToTraverse, i => OctreeNodeProcess.Process(node._children[i], face)); } // If there is any disjoint, we need to keep this node as it is. This should be done after we processed all the children to be traversed!! if (disjointCount > 0 && disjointCount < 8) { return; } int countGrandChildren = 0; // If there is no disjoint, we need to check whether all children are terminal (i.e. child._children.Count == 0) foreach (OctreeNode child in node._children) { countGrandChildren += child._children.Count; } // All children are terminal and no disjoint (by implication of previous steps). Remove children if (countGrandChildren == 0) { node._children.Clear(); node._flag = PolyhedronIntersectEnum.IntersectOrInside; return; } } else { // at _depth == Octree.MaxDepth there is nothing else to do since the test has been done at the parent level and when entering this stage, the test has determined // that the cell is intersected with the polyH } return; }
public static bool Parallels(Plane3D P1, Face3D F1) { return(Vector3D.Parallels(P1.normalVector, F1.basePlane.normalVector)); }