public Face3D(List <Point3D> vertices) { _vertices = vertices; //for (int i = 0; i < vertices.Count; i++) //{ // LineSegment3D edge; // if (i == vertices.Count - 1) // edge = new LineSegment3D(vertices[i], vertices[0]); // else // edge = new LineSegment3D(vertices[i], vertices[i + 1]); // _boundaryLines.Add(edge); // if (i > 0 && i < vertices.Count) // { // if (_boundaryLines[i].baseLine.direction != _boundaryLines[i-1].baseLine.direction) // _nonColinearEdgesIdx.Add(i-1); // } // if (i == vertices.Count -1 ) // if (_boundaryLines[i].baseLine.direction != _boundaryLines[0].baseLine.direction) // _nonColinearEdgesIdx.Add(i); //} generateEdges(vertices, out _boundaryLines, out _nonColinearEdgesIdx); //_basePlane = new Plane3D(_vertices[0], _boundaryLines[_nonColinearEdgesIdx[0]].baseLine.direction, _boundaryLines[_nonColinearEdgesIdx[1]].baseLine.direction); // Use Newell's method to calculate normal because any vertices > 3 can be concave Vector3D faceNormal = normalByNewellMethod(_vertices); _basePlane = new Plane3D(_vertices[0], faceNormal); containingBB = new BoundingBox3D(_vertices); }
/// <summary> /// This is to support initialization of Face3D with holes. The list contains multiple lists, the first one should be the outer list and the rest are the inner lists /// Currently support of holes is still very scant, just be able to capture the data. Everything else (operations) are only working for the outer loop without consideration of the holes /// </summary> /// <param name="vertices"></param> public Face3D(List <List <Point3D> > vertices) { // Initialize the outer boundary information _vertices = vertices[0]; generateEdges(vertices[0], out _boundaryLines, out _nonColinearEdgesIdx); //_basePlane = new Plane3D(_vertices[0], _boundaryLines[_nonColinearEdgesIdx[0]].baseLine.direction, _boundaryLines[_nonColinearEdgesIdx[1]].baseLine.direction); // Use Newell's method to calculate normal because any vertices > 3 can be concave Vector3D faceNormal = normalByNewellMethod(_vertices); _basePlane = new Plane3D(_vertices[0], faceNormal); containingBB = new BoundingBox3D(_vertices); // Now add the inner boundary informations for (int i = 1; i < vertices.Count; i++) { List <Point3D> innerLoop = new List <Point3D>(); List <LineSegment3D> innerBound = new List <LineSegment3D>(); List <int> nonColinearBoundIdx = new List <int>(); _innerVertices.Add(vertices[i]); generateEdges(vertices[i], out innerBound, out nonColinearBoundIdx); _innerBoundaries.Add(innerBound); } }
public static bool Overlaps(Plane3D P1, LineSegment3D LS) { double res = Vector3D.DotProduct(P1.normalVector, LS.baseLine.direction); bool pOnPlane = pointOnPlane(P1, LS.startPoint); // if the normals are the same and point in P2 is also point in P1, the two planes are overlapped return(MathUtils.equalTol(res, 0.0, MathUtils.defaultTol) && pOnPlane); }
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); }
/// <summary> /// Test whether 2 planes overlapped /// </summary> /// <param name="P1"></param> /// <param name="P2"></param> /// <returns></returns> public static bool Overlaps(Plane3D P1, Plane3D P2) { bool parallel = Vector3D.Parallels(P1.normalVector, P2.normalVector); bool pOnPlane = pointOnPlane(P1, P2.point); // if the normals are the same and point in P2 is also point in P1, the two planes are overlapped return(parallel && pOnPlane); }
public static bool Parallels(Plane3D P1, LineSegment3D LS) { double res = Vector3D.DotProduct(P1.normalVector, LS.baseLine.direction); if (MathUtils.equalTol(res, 0.0, MathUtils.defaultTol)) { return(true); } return(false); }
public static List <Face3D> exclFacesOutsideOfBound(List <Face3D> faces, BoundingBox3D bound, UInt16 axes) { Plane3D lowerBoundX = new Plane3D(bound.LLB, new Vector3D(1.0, 0.0, 0.0)); Plane3D lowerBoundY = new Plane3D(bound.LLB, new Vector3D(0.0, 1.0, 0.0)); Plane3D lowerBoundZ = new Plane3D(bound.LLB, new Vector3D(0.0, 0.0, 1.0)); Plane3D upperBoundX = new Plane3D(bound.URT, new Vector3D(1.0, 0.0, 0.0)); Plane3D upperBoundY = new Plane3D(bound.URT, new Vector3D(0.0, 1.0, 0.0)); Plane3D upperBoundZ = new Plane3D(bound.URT, new Vector3D(0.0, 0.0, 1.0)); List <Face3D> reducedList = faces; // filter each direction if ((axes & 0x100) == 0x100) { // filter X direction if (reducedList.Count > 0) { reducedList = exclFacesLeftOfAxis(reducedList, lowerBoundX); } if (reducedList.Count > 0) { reducedList = exclFacesRightOfAxis(reducedList, upperBoundX); } } if ((axes & 0x010) == 0x010) { // filter Y direction if (reducedList.Count > 0) { reducedList = exclFacesLeftOfAxis(reducedList, lowerBoundY); } if (reducedList.Count > 0) { reducedList = exclFacesRightOfAxis(reducedList, upperBoundY); } } if ((axes & 0x001) == 0x001) { // filter Z direction if (reducedList.Count > 0) { reducedList = exclFacesLeftOfAxis(reducedList, lowerBoundZ); } if (reducedList.Count > 0) { reducedList = exclFacesRightOfAxis(reducedList, upperBoundZ); } } return(reducedList); }
/// <summary> /// Test whether two planes intersect /// </summary> /// <param name="P1">Plane 1</param> /// <param name="P2">Plane 2</param> /// <param name="intersectingLine">Resulting intersection line</param> /// <returns></returns> public static bool PPintersect(Plane3D P1, Plane3D P2, out Line3D intersectingLine) { intersectingLine = new Line3D(); if (Vector3D.Parallels(P1.normalVector, P2.normalVector)) { return(false); // Planes are parallel to each other } intersectingLine.direction = Vector3D.CrossProduct(P1.normalVector, P2.normalVector); // To find the point on the line, we can use 3 plane intersection with the 3rd plane with the normal as a cross product of P1 and P2 to guarantee 1 point intersection. It passes through the origin Vector3D n3 = Vector3D.CrossProduct(P1.normalVector, P2.normalVector); double da = 1 / (Vector3D.DotProduct(P1.normalVector, Vector3D.CrossProduct(P2.normalVector, n3))); Vector3D vp = (-P1.parConstant * (Vector3D.CrossProduct(P2.normalVector, n3)) - P2.parConstant * (Vector3D.CrossProduct(n3, P1.normalVector))) * da; intersectingLine.point.X = vp.X; intersectingLine.point.Y = vp.Y; intersectingLine.point.Z = vp.Z; //if ((Math.Abs(intersectingLine.direction.Z) > Math.Abs(intersectingLine.direction.X)) && (Math.Abs(intersectingLine.direction.Z) > Math.Abs(intersectingLine.direction.Y))) //{// Z=0 // intersectingLine.point.Y = (P1.normalVector.X * P2.parConstant - P2.normalVector.X * P1.parConstant) // / (P1.normalVector.Y * P2.normalVector.X - P1.normalVector.X * P2.normalVector.Y); // if (!MathUtils.equalTol(P1.normalVector.X, 0.0, MathUtils.defaultTol)) // intersectingLine.point.X = (-P1.parConstant - P1.normalVector.Y * intersectingLine.point.Y) / P1.normalVector.X; // else // intersectingLine.point.X = (-P2.parConstant - P2.normalVector.Y * intersectingLine.point.Y) / P2.normalVector.X; // intersectingLine.point.Z = 0.0; //} //else if ((Math.Abs(intersectingLine.direction.Y) > Math.Abs(intersectingLine.direction.X)) && (Math.Abs(intersectingLine.direction.Y) > Math.Abs(intersectingLine.direction.Z))) //{// Y=0 // intersectingLine.point.Z = (P1.normalVector.X * P2.parConstant - P2.normalVector.X * P1.parConstant) // / (P1.normalVector.Z * P2.normalVector.X - P1.normalVector.X * P2.normalVector.Z); // if (!MathUtils.equalTol(P1.normalVector.X, 0.0, MathUtils.defaultTol)) // intersectingLine.point.X = (-P1.parConstant - P1.normalVector.Z * intersectingLine.point.Z) / P1.normalVector.X; // else // intersectingLine.point.X = (-P2.parConstant - P2.normalVector.Z * intersectingLine.point.Z) / P2.normalVector.X; // intersectingLine.point.Y = 0.0; //} //else //{// X=0 // intersectingLine.point.Y = (P1.normalVector.Z * P2.parConstant - P2.normalVector.Z * P1.parConstant) // / (P1.normalVector.Y * P2.normalVector.Z - P1.normalVector.Z * P2.normalVector.Y); // if (!MathUtils.equalTol(P1.normalVector.Z, 0.0, MathUtils.defaultTol)) // intersectingLine.point.Z = (-P1.parConstant - P1.normalVector.Y * intersectingLine.point.Y) / P1.normalVector.Z; // else // intersectingLine.point.Z = (-P2.parConstant - P2.normalVector.Y * intersectingLine.point.Y) / P2.normalVector.Z; // intersectingLine.point.X = 0.0; //} return(true); }
public static bool validateFace(List <List <Point3D> > vertexLists) { if (vertexLists.Count < 1) { return(false); } foreach (List <Point3D> pList in vertexLists) { // Face has less than minimum 3 vertices if (pList.Count < 3) { return(false); } List <LineSegment3D> boundaryLines; List <int> nonColinearEdgesIdx; // There is no enough non-colinear edges to form a valid Face generateEdges(pList, out boundaryLines, out nonColinearEdgesIdx); if (nonColinearEdgesIdx.Count < 2) { return(false); } //Plane3D basePlane = new Plane3D(pList[0], boundaryLines[nonColinearEdgesIdx[0]].baseLine.direction, boundaryLines[nonColinearEdgesIdx[1]].baseLine.direction); // Use Newell's method to calculate normal because any vertices > 3 can be concave Vector3D faceNormal = normalByNewellMethod(pList); Plane3D basePlane = new Plane3D(pList[0], faceNormal); // If we can't get a normal, then the face is most likely not valid if (double.IsNaN(basePlane.normalVector.X) || double.IsNaN(basePlane.normalVector.Y) || double.IsNaN(basePlane.normalVector.Z)) { return(false); } if (basePlane.normalVector.X == 0.0 && basePlane.normalVector.Y == 0.0 && basePlane.normalVector.Z == 0.0) { return(false); } // Skip the check for point on plane as it may not be as critical and it is too sensitive to tolerance //foreach (Point3D p in pList) //{ // // Test all points are on the plane // if (!Plane3D.pointOnPlane(basePlane, p)) // return false; //} } return(true); }
/// <summary> /// This function return reduced list of faces that is entirely on the RIGHT of the specified Axis (only work on Axis parallel to X, or Y, or Z) /// The funcion is used for optimizing intersection test between the polyhedron and the Axis-align bounding box (e.g. Octree cell) /// </summary> /// <param name="axisLoc">The axis location. Must be X only, or Y only, or Z only</param> /// <returns></returns> public static List <Face3D> exclFacesLeftOfAxis(List <Face3D> faces, Plane3D axisPl) { List <Face3D> facesRightOfAxis = new List <Face3D>(); // Only deal with one axis set, either A, Y or Z, otherwise null List will be returned if ((axisPl.normalVector.Y == 0.0 && axisPl.normalVector.Z == 0.0) || (axisPl.normalVector.X == 0.0 && axisPl.normalVector.Y == 0.0) || (axisPl.normalVector.X == 0.0 && axisPl.normalVector.Z == 0.0)) { for (int i = 0; i < faces.Count; i++) { bool left = true; // Test all face boundaries are beyond the axis location specified for (int j = 0; j < faces[i].boundaries.Count; j++) { // It is sufficient to stop checking if any point of any of the boundaries lies behind the Axis location if (axisPl.normalVector.X != 0.0) { if (!(faces[i].boundaries[j].startPoint.X < axisPl.point.X && faces[i].boundaries[j].endPoint.X < axisPl.point.X)) { left = false; break; } } else if (axisPl.normalVector.Y != 0.0) { if (!(faces[i].boundaries[j].startPoint.Y < axisPl.point.Y && faces[i].boundaries[j].endPoint.Y < axisPl.point.Y)) { left = false; break; } } if (axisPl.normalVector.Z != 0.0) { if (!(faces[i].boundaries[j].startPoint.Z < axisPl.point.Z && faces[i].boundaries[j].endPoint.Z < axisPl.point.Z)) { left = false; break; } } } if (left == false) { facesRightOfAxis.Add(faces[i]); } } } return(facesRightOfAxis); }
/// <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> /// Plane and a line intersection /// </summary> /// <param name="P1">Plane</param> /// <param name="L1">Line</param> /// <param name="intersectingPoint">Point of intersection</param> /// <returns></returns> public static bool PLintersect(Plane3D P1, Line3D L1, out Point3D intersectingPoint) { intersectingPoint = new Point3D(); double denom = Vector3D.DotProduct(P1.normalVector, L1.direction); if (MathUtils.equalTol(denom, 0.0, MathUtils.defaultTol)) { return(false); // Normal and the lines are perpendicular to each other: line is parallel to the plane, no intersection } double r = Vector3D.DotProduct(P1.normalVector, new Vector3D(P1.point.X - L1.point.X, P1.point.Y - L1.point.Y, P1.point.Z - L1.point.Z)) / denom; intersectingPoint.X = L1.point.X + r * L1.direction.X; intersectingPoint.Y = L1.point.Y + r * L1.direction.Y; intersectingPoint.Z = L1.point.Z + r * L1.direction.Z; return(true); }
/// <summary> /// This function return reduced list of faces that is entirely on the LEFT of the specified Axis (only work on Axis parallel to X, or Y, or Z) /// The funcion is used for optimizing intersection test between the polyhedron and the Axis-align bounding box (e.g. Octree cell) /// </summary> /// <param name="axisLoc">The axis location. Must be either X only, or Y only, or Z only</param> /// <returns></returns> public static List <Face3D> inclFacesBeyondAxis(List <Face3D> faces, Plane3D axisPl) { List <Face3D> facesBeyond = new List <Face3D>(); // Only deal with one axis set, either X, Y or Z, otherwise null List will be returned if ((axisPl.normalVector.Y == 0.0 && axisPl.normalVector.Z == 0.0) || (axisPl.normalVector.X == 0.0 && axisPl.normalVector.Y == 0.0) || (axisPl.normalVector.X == 0.0 && axisPl.normalVector.Z == 0.0)) { for (int i = 0; i < faces.Count; i++) { for (int j = 0; j < faces[i].boundaries.Count; j++) { // Sufficient to test whether there is any of the end point of the segment is beyond the Axis location if (axisPl.normalVector.X != 0.0) { if (faces[i].boundaries[j].startPoint.X >= axisPl.point.X || faces[i].boundaries[j].endPoint.X >= axisPl.point.X) { facesBeyond.Add(faces[i]); break; } } else if (axisPl.normalVector.Y != 0.0) { if (faces[i].boundaries[j].startPoint.Y >= axisPl.point.Y || faces[i].boundaries[j].endPoint.Y >= axisPl.point.Y) { facesBeyond.Add(faces[i]); break; } } if (axisPl.normalVector.Z != 0.0) { if (faces[i].boundaries[j].startPoint.Z >= axisPl.point.Z || faces[i].boundaries[j].endPoint.Z >= axisPl.point.Z) { facesBeyond.Add(faces[i]); break; } } } } } return(facesBeyond); }
/// <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); }
public void Reverse() { // First reverse the vertex list, and then regenerate the rest _vertices.Reverse(); _boundaryLines.Clear(); _nonColinearEdgesIdx.Clear(); for (int i = 0; i < vertices.Count; i++) { LineSegment3D edge; if (i == vertices.Count - 1) { edge = new LineSegment3D(vertices[i], vertices[0]); } else { edge = new LineSegment3D(vertices[i], vertices[i + 1]); } _boundaryLines.Add(edge); if (i > 0 && i < vertices.Count) { if (_boundaryLines[i].baseLine.direction != _boundaryLines[i - 1].baseLine.direction) { _nonColinearEdgesIdx.Add(i - 1); } } if (i == vertices.Count - 1) { if (_boundaryLines[i].baseLine.direction != _boundaryLines[0].baseLine.direction) { _nonColinearEdgesIdx.Add(i); } } } _basePlane = new Plane3D(vertices[0], _boundaryLines[_nonColinearEdgesIdx[0]].baseLine.direction, _boundaryLines[_nonColinearEdgesIdx[1]].baseLine.direction); containingBB = new BoundingBox3D(vertices); }
/// <summary> /// Test whether a point P1 lies on the plane PL1 /// </summary> /// <param name="PL1">Plane</param> /// <param name="P1">Point</param> /// <param name="distance">return the distance. Needed to check whether the point is actually on the plabe: distance=0</param> /// <returns></returns> public static bool pointOnPlane(Plane3D PL1, Point3D P1, out double distance) { distance = distPoint2Plane(PL1, P1); return(MathUtils.equalTol(distance, 0.0)); }
/// <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); }
/// <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 bool Parallels(Plane3D P1, Face3D F1) { return(Vector3D.Parallels(P1.normalVector, F1.basePlane.normalVector)); }
/// <summary> /// Test whether a point P1 lies on the plane PL1 /// </summary> /// <param name="PL1">Plane</param> /// <param name="P1">Point</param> /// <returns></returns> public static bool pointOnPlane(Plane3D PL1, Point3D P1) { return(MathUtils.equalTol(distPoint2Plane(PL1, P1), 0.0)); }
/// <summary> /// Distance from a point to a plane /// </summary> /// <param name="PL1">Plane</param> /// <param name="P1">Point</param> /// <returns></returns> public static double distPoint2Plane(Plane3D PL1, Point3D P1) { return(Vector3D.DotProduct(PL1.normalVector, new Vector3D(P1.X - PL1.point.X, P1.Y - PL1.point.Y, P1.Z - PL1.point.Z))); }
public static bool Parallels(Plane3D P1, Plane3D P2) { return(Vector3D.Parallels(P1.normalVector, P2.normalVector)); }