/// <summary> /// Method used to add a face properly for internal methods /// </summary> /// <param name="v1">a face vertex</param> /// <param name="v2">a face vertex</param> /// <param name="v3">a face vertex</param> /// <returns></returns> private void AddFaceFromSplit(Vertex v1, Vertex v2, Vertex v3, Stack <CsgFace> facesFromSplit) { if (!(v1.Equals(v2) || v1.Equals(v3) || v2.Equals(v3))) { CsgFace face = new CsgFace(v1, v2, v3); if (face.GetArea() > EqualityTolerance) { bool exists = false; foreach (var test in facesFromSplit) { if (test.Equals(face)) { exists = true; break; } } if (!exists) { Faces.Insert(face, face.GetBound()); facesFromSplit.Push(face); } } } }
/// <summary> /// Face breaker for VERTEX-FACE-FACE / FACE-FACE-VERTEX /// </summary> /// <param name="faceIndex">face index in the faces array</param> /// <param name="newPos">new vertex position</param> /// <param name="endVertex">vertex used for the split</param> private bool BreakFaceInThree(CsgFace face, Vector3 newPos, Stack <CsgFace> facesFromSplit) { // O // -*- // - * - // - * - // - X - // - * * - // O-*--------*O Vertex vertex = AddVertex(newPos, FaceStatus.Boundary); if (face.v1.Position == vertex.Position || face.v2.Position == vertex.Position || face.v2.Position == vertex.Position) // it is not new { // if the vertex we are adding is any of the existing vertices then don't add any return(false); } AddFaceFromSplit(face.v1, face.v2, vertex, facesFromSplit); AddFaceFromSplit(face.v2, face.v3, vertex, facesFromSplit); AddFaceFromSplit(face.v3, face.v1, vertex, facesFromSplit); Faces.Remove(face); return(true); }
public bool Equals(CsgFace face) { bool cond1 = v1.Equals(face.v1) && v2.Equals(face.v2) && v3.Equals(face.v3); bool cond2 = v1.Equals(face.v2) && v2.Equals(face.v3) && v3.Equals(face.v1); bool cond3 = v1.Equals(face.v3) && v2.Equals(face.v1) && v3.Equals(face.v2); return(cond1 || cond2 || cond3); }
/// <summary> /// Face breaker for VERTEX-FACE-EDGE / EDGE-FACE-VERTEX /// </summary> /// <param name="faceIndex">face index in the faces array</param> /// <param name="newPos">new vertex position</param> /// <param name="endVertex">vertex used for splitting</param> private bool BreakFaceInTwo(CsgFace face, Vector3 newPos, Vertex endVertex, Stack <CsgFace> facesFromSplit) { // O // - - // - - // - - // - - // - - // O-----------O // TODO: make sure we are not creating extra Vertices and not cleaning them up Vertex vertex = AddVertex(newPos, FaceStatus.Boundary); if (endVertex.Equals(face.v1)) { // don't add it if it is the same as the face we have if (!face.v1.Equals(vertex) && !face.v2.Equals(vertex)) { AddFaceFromSplit(face.v1, vertex, face.v3, facesFromSplit); AddFaceFromSplit(vertex, face.v2, face.v3, facesFromSplit); Faces.Remove(face); return(true); } } else if (endVertex.Equals(face.v2)) { // don't add it if it is the same as the face we have if (!face.v2.Equals(vertex) && !face.v3.Equals(vertex)) { AddFaceFromSplit(face.v2, vertex, face.v1, facesFromSplit); AddFaceFromSplit(vertex, face.v3, face.v1, facesFromSplit); Faces.Remove(face); return(true); } } else { // don't add it if it is the same as the face we have if (!face.v1.Equals(vertex) && !face.v3.Equals(vertex)) { AddFaceFromSplit(face.v3, vertex, face.v2, facesFromSplit); AddFaceFromSplit(vertex, face.v1, face.v2, facesFromSplit); Faces.Remove(face); return(true); } } return(false); }
/// <summary> /// Clones the face object /// </summary> /// <returns>cloned face object</returns> public CsgFace Clone() { CsgFace clone = new CsgFace(); clone.v1 = v1.Clone(); clone.v2 = v2.Clone(); clone.v3 = v3.Clone(); clone.center = center; clone.Status = Status; return(clone); }
/// <summary> /// Face breaker for EDGE-FACE-EDGE /// </summary> /// <param name="faceIndex">face index in the faces array</param> /// <param name="newPos1">new vertex position</param> /// <param name="newPos2">new vertex position</param> /// <param name="startVertex">vertex used for the new faces creation</param> /// <param name="endVertex">vertex used for the new faces creation</param> private bool BreakFaceInThree(CsgFace face, Vector3 newPos1, Vector3 newPos2, Vertex startVertex, Vertex endVertex, Stack <CsgFace> facesFromSplit) { // O // - - // - - // - - // - - // - - // O-----------O Vertex vertex1 = AddVertex(newPos1, FaceStatus.Boundary); Vertex vertex2 = AddVertex(newPos2, FaceStatus.Boundary); if (startVertex.Equals(face.v1) && endVertex.Equals(face.v2)) { AddFaceFromSplit(face.v1, vertex1, vertex2, facesFromSplit); AddFaceFromSplit(face.v1, vertex2, face.v3, facesFromSplit); AddFaceFromSplit(vertex1, face.v2, vertex2, facesFromSplit); } else if (startVertex.Equals(face.v2) && endVertex.Equals(face.v1)) { AddFaceFromSplit(face.v1, vertex2, vertex1, facesFromSplit); AddFaceFromSplit(face.v1, vertex1, face.v3, facesFromSplit); AddFaceFromSplit(vertex2, face.v2, vertex1, facesFromSplit); } else if (startVertex.Equals(face.v2) && endVertex.Equals(face.v3)) { AddFaceFromSplit(face.v2, vertex1, vertex2, facesFromSplit); AddFaceFromSplit(face.v2, vertex2, face.v1, facesFromSplit); AddFaceFromSplit(vertex1, face.v3, vertex2, facesFromSplit); } else if (startVertex.Equals(face.v3) && endVertex.Equals(face.v2)) { AddFaceFromSplit(face.v2, vertex2, vertex1, facesFromSplit); AddFaceFromSplit(face.v2, vertex1, face.v1, facesFromSplit); AddFaceFromSplit(vertex2, face.v3, vertex1, facesFromSplit); } else if (startVertex.Equals(face.v3) && endVertex.Equals(face.v1)) { AddFaceFromSplit(face.v3, vertex1, vertex2, facesFromSplit); AddFaceFromSplit(face.v3, vertex2, face.v2, facesFromSplit); AddFaceFromSplit(vertex1, face.v1, vertex2, facesFromSplit); } else { AddFaceFromSplit(face.v3, vertex2, vertex1, facesFromSplit); AddFaceFromSplit(face.v3, vertex1, face.v2, facesFromSplit); AddFaceFromSplit(vertex2, face.v1, vertex1, facesFromSplit); } Faces.Remove(face); return(true); }
/// <summary> /// Face breaker for FACE-FACE-FACE /// </summary> /// <param name="faceIndex">face index in the faces array</param> /// <param name="facePos1">new vertex position</param> /// <param name="facePos2">new vertex position</param> /// <param name="linedVertex">linedVertex what vertex is more lined with the intersection found</param> private bool BreakFaceInFive(CsgFace face, Vector3 facePos1, Vector3 facePos2, int linedVertex, Stack <CsgFace> facesFromSplit) { // O // - - // - - // - - // - X - // - X - // O-----------O Vertex faceVertex1 = AddVertex(facePos1, FaceStatus.Boundary); bool faceVertex1Exists = faceVertex1 != vertices[vertices.Count - 1]; Vertex faceVertex2 = AddVertex(facePos2, FaceStatus.Boundary); bool faceVertex2Exists = faceVertex2 != vertices[vertices.Count - 1]; if (faceVertex1Exists && faceVertex2Exists) { vertices.RemoveAt(vertices.Count - 1); vertices.RemoveAt(vertices.Count - 1); return(false); } if (linedVertex == 1) { AddFaceFromSplit(face.v2, face.v3, faceVertex1, facesFromSplit); AddFaceFromSplit(face.v2, faceVertex1, faceVertex2, facesFromSplit); AddFaceFromSplit(face.v3, faceVertex2, faceVertex1, facesFromSplit); AddFaceFromSplit(face.v2, faceVertex2, face.v1, facesFromSplit); AddFaceFromSplit(face.v3, face.v1, faceVertex2, facesFromSplit); } else if (linedVertex == 2) { AddFaceFromSplit(face.v3, face.v1, faceVertex1, facesFromSplit); AddFaceFromSplit(face.v3, faceVertex1, faceVertex2, facesFromSplit); AddFaceFromSplit(face.v1, faceVertex2, faceVertex1, facesFromSplit); AddFaceFromSplit(face.v3, faceVertex2, face.v2, facesFromSplit); AddFaceFromSplit(face.v1, face.v2, faceVertex2, facesFromSplit); } else { AddFaceFromSplit(face.v1, face.v2, faceVertex1, facesFromSplit); AddFaceFromSplit(face.v1, faceVertex1, faceVertex2, facesFromSplit); AddFaceFromSplit(face.v2, faceVertex2, faceVertex1, facesFromSplit); AddFaceFromSplit(face.v1, faceVertex2, face.v3, facesFromSplit); AddFaceFromSplit(face.v2, face.v3, faceVertex2, facesFromSplit); } Faces.Remove(face); return(true); }
/// <summary> /// Face breaker for EDGE-FACE-FACE / FACE-FACE-EDGE /// </summary> /// <param name="faceIndex">face index in the faces array</param> /// <param name="edgePos">new vertex position</param> /// <param name="facePos">new vertex position</param> /// <param name="endVertex">vertex used for the split</param> private bool BreakFaceInFour(CsgFace face, Vector3 edgePos, Vector3 facePos, Vertex endVertex, Stack <CsgFace> facesFromSplit) { // 2 // -*- // - * - // - * E // - * * - // - F - // - * * - // - * * - // 3---------------1 Vertex edgeVertex = AddVertex(edgePos, FaceStatus.Boundary); bool edgeExists = edgeVertex != vertices[vertices.Count - 1]; Vertex faceVertex = AddVertex(facePos, FaceStatus.Boundary); bool faceExists = faceVertex != vertices[vertices.Count - 1]; if (faceExists && edgeExists) { vertices.RemoveAt(vertices.Count - 1); vertices.RemoveAt(vertices.Count - 1); return(false); } // check that we are not adding back in the same face we are removing if (endVertex.Equals(face.v1)) { AddFaceFromSplit(face.v1, edgeVertex, faceVertex, facesFromSplit); AddFaceFromSplit(edgeVertex, face.v2, faceVertex, facesFromSplit); AddFaceFromSplit(face.v2, face.v3, faceVertex, facesFromSplit); AddFaceFromSplit(face.v3, face.v1, faceVertex, facesFromSplit); } else if (endVertex.Equals(face.v2)) { AddFaceFromSplit(face.v2, edgeVertex, faceVertex, facesFromSplit); AddFaceFromSplit(edgeVertex, face.v3, faceVertex, facesFromSplit); AddFaceFromSplit(face.v3, face.v1, faceVertex, facesFromSplit); AddFaceFromSplit(face.v1, face.v2, faceVertex, facesFromSplit); } else { AddFaceFromSplit(face.v3, edgeVertex, faceVertex, facesFromSplit); AddFaceFromSplit(edgeVertex, face.v1, faceVertex, facesFromSplit); AddFaceFromSplit(face.v1, face.v2, faceVertex, facesFromSplit); AddFaceFromSplit(face.v2, face.v3, faceVertex, facesFromSplit); } Faces.Remove(face); return(true); }
private CsgFace AddFace(Vertex v1, Vertex v2, Vertex v3) { if (!(v1.Equals(v2) || v1.Equals(v3) || v2.Equals(v3))) { CsgFace face = new CsgFace(v1, v2, v3); if (face.GetArea() > EqualityTolerance) { Faces.Insert(face, face.GetBound()); return(face); } } return(null); }
/// <summary> /// Face breaker for VERTEX-EDGE-EDGE / EDGE-EDGE-VERTEX /// </summary> /// <param name="faceIndex">face index in the faces array</param> /// <param name="newPos">new vertex position</param> /// <param name="splitEdge">edge that will be split</param> private bool BreakFaceInTwo(CsgFace face, Vector3 newPos, int splitEdge, Stack <CsgFace> facesFromSplit) { // O // -*- // - * - // - * - // - * - // - * - // O-----X-----O Vertex vertex = AddVertex(newPos, FaceStatus.Boundary); if (vertex != vertices[vertices.Count - 1]) { // The added vertex is one of the existing vertices. So we would only add the same face we are removing. return(false); } if (splitEdge == 1) { AddFaceFromSplit(face.v1, vertex, face.v3, facesFromSplit); AddFaceFromSplit(vertex, face.v2, face.v3, facesFromSplit); } else if (splitEdge == 2) { if (!face.v3.Equals(vertex)) { AddFaceFromSplit(face.v2, vertex, face.v1, facesFromSplit); } AddFaceFromSplit(vertex, face.v3, face.v1, facesFromSplit); } else { AddFaceFromSplit(face.v3, vertex, face.v2, facesFromSplit); AddFaceFromSplit(vertex, face.v1, face.v2, facesFromSplit); } Faces.Remove(face); return(true); }
/// <summary> /// Constructor for a line.The line created is the intersection between two planes /// </summary> /// <param name="face1">face representing one of the planes</param> /// <param name="face2">face representing one of the planes</param> public Line(CsgFace face1, CsgFace face2) { Vector3 normalFace1 = face1.Normal; Vector3 normalFace2 = face2.Normal; //direction: cross product of the faces normals Direction = Vector3Ex.Cross(normalFace1, normalFace2); //if direction length is not zero (the planes aren't parallel )... if (!(Direction.Length < EqualityTolerance)) { //getting a line point, zero is set to a coordinate whose direction //component isn't zero (line intersecting its origin plan) startPoint = new Vector3(); double d1 = -(normalFace1.X * face1.v1.Position.X + normalFace1.Y * face1.v1.Position.Y + normalFace1.Z * face1.v1.Position.Z); double d2 = -(normalFace2.X * face2.v1.Position.X + normalFace2.Y * face2.v1.Position.Y + normalFace2.Z * face2.v1.Position.Z); if (Math.Abs(Direction.X) > EqualityTolerance) { startPoint.X = 0; startPoint.Y = (d2 * normalFace1.Z - d1 * normalFace2.Z) / Direction.X; startPoint.Z = (d1 * normalFace2.Y - d2 * normalFace1.Y) / Direction.X; } else if (Math.Abs(Direction.Y) > EqualityTolerance) { startPoint.X = (d1 * normalFace2.Z - d2 * normalFace1.Z) / Direction.Y; startPoint.Y = 0; startPoint.Z = (d2 * normalFace1.X - d1 * normalFace2.X) / Direction.Y; } else { startPoint.X = (d2 * normalFace1.Y - d1 * normalFace2.Y) / Direction.Z; startPoint.Y = (d1 * normalFace2.X - d2 * normalFace1.X) / Direction.Z; startPoint.Z = 0; } } Direction.Normalize(); }
/// <summary> /// Split an individual face /// </summary> /// <param name="faceIndex">face index in the array of faces</param> /// <param name="segment1">segment representing the intersection of the face with the plane</param> /// <param name="segment2">segment representing the intersection of other face with the plane of the current face plane</param> private bool SplitFace(CsgFace face, Segment segment1, Segment segment2, Stack <CsgFace> facesFromSplit) { Vector3 startPos, endPos; SegmentEnd startType, endType, middleType; double startDist, endDist; Vertex startVertex = segment1.StartVertex; Vertex endVertex = segment1.EndVertex; //starting point: deeper starting point if (segment2.StartDistance > segment1.StartDistance + EqualityTolerance) { startDist = segment2.StartDistance; startType = segment1.MiddleType; startPos = segment2.StartPosition; } else { startDist = segment1.StartDistance; startType = segment1.StartType; startPos = segment1.StartPosition; } //ending point: deepest ending point if (segment2.EndDistance < segment1.EndDistance - EqualityTolerance) { endDist = segment2.EndDistance; endType = segment1.MiddleType; endPos = segment2.EndPosition; } else { endDist = segment1.EndDistance; endType = segment1.EndType; endPos = segment1.EndPosition; } middleType = segment1.MiddleType; if (startType == SegmentEnd.Vertex) { //set vertex to BOUNDARY if it is start type startVertex.Status = FaceStatus.Boundary; } if (endType == SegmentEnd.Vertex) { //set vertex to BOUNDARY if it is end type endVertex.Status = FaceStatus.Boundary; } if (startType == SegmentEnd.Vertex && endType == SegmentEnd.Vertex) { //VERTEX-_______-VERTEX return(false); } else if (middleType == SegmentEnd.Edge) { //______-EDGE-______ //gets the edge int splitEdge; if ((startVertex == face.v1 && endVertex == face.v2) || (startVertex == face.v2 && endVertex == face.v1)) { splitEdge = 1; } else if ((startVertex == face.v2 && endVertex == face.v3) || (startVertex == face.v3 && endVertex == face.v2)) { splitEdge = 2; } else { splitEdge = 3; } if (startType == SegmentEnd.Vertex) { //VERTEX-EDGE-EDGE return(BreakFaceInTwo(face, endPos, splitEdge, facesFromSplit)); } else if (endType == SegmentEnd.Vertex) { //EDGE-EDGE-VERTEX return(BreakFaceInTwo(face, startPos, splitEdge, facesFromSplit)); } else if (startDist == endDist) { // EDGE-EDGE-EDGE return(BreakFaceInTwo(face, endPos, splitEdge, facesFromSplit)); } else { if ((startVertex == face.v1 && endVertex == face.v2) || (startVertex == face.v2 && endVertex == face.v3) || (startVertex == face.v3 && endVertex == face.v1)) { return(BreakFaceInThree(face, startPos, endPos, splitEdge, facesFromSplit)); } else { return(BreakFaceInThree(face, endPos, startPos, splitEdge, facesFromSplit)); } } } //______-FACE-______ else if (startType == SegmentEnd.Vertex && endType == SegmentEnd.Edge) { //VERTEX-FACE-EDGE return(BreakFaceInTwo(face, endPos, endVertex, facesFromSplit)); } else if (startType == SegmentEnd.Edge && endType == SegmentEnd.Vertex) { //EDGE-FACE-VERTEX return(BreakFaceInTwo(face, startPos, startVertex, facesFromSplit)); } else if (startType == SegmentEnd.Vertex && endType == SegmentEnd.Face) { //VERTEX-FACE-FACE return(BreakFaceInThree(face, endPos, facesFromSplit)); } else if (startType == SegmentEnd.Face && endType == SegmentEnd.Vertex) { //FACE-FACE-VERTEX return(BreakFaceInThree(face, startPos, facesFromSplit)); } else if (startType == SegmentEnd.Edge && endType == SegmentEnd.Edge) { //EDGE-FACE-EDGE return(BreakFaceInThree(face, startPos, endPos, startVertex, endVertex, facesFromSplit)); } else if (startType == SegmentEnd.Edge && endType == SegmentEnd.Face) { //EDGE-FACE-FACE return(BreakFaceInFour(face, startPos, endPos, startVertex, facesFromSplit)); } else if (startType == SegmentEnd.Face && endType == SegmentEnd.Edge) { //FACE-FACE-EDGE return(BreakFaceInFour(face, endPos, startPos, endVertex, facesFromSplit)); } else if (startType == SegmentEnd.Face && endType == SegmentEnd.Face) { //FACE-FACE-FACE Vector3 segmentVector = new Vector3(startPos.X - endPos.X, startPos.Y - endPos.Y, startPos.Z - endPos.Z); //if the intersection segment is a point only... if (Math.Abs(segmentVector.X) < EqualityTolerance && Math.Abs(segmentVector.Y) < EqualityTolerance && Math.Abs(segmentVector.Z) < EqualityTolerance) { return(BreakFaceInThree(face, startPos, facesFromSplit)); } //gets the vertex more lined with the intersection segment double dot1 = Math.Abs(Vector3.Dot(segmentVector, (endPos - face.v1.Position).GetNormal())); double dot2 = Math.Abs(Vector3.Dot(segmentVector, (endPos - face.v2.Position).GetNormal())); double dot3 = Math.Abs(Vector3.Dot(segmentVector, (endPos - face.v3.Position).GetNormal())); int linedVertex; Vector3 linedVertexPos; if (dot1 > dot2 && dot1 > dot3) { linedVertex = 1; linedVertexPos = face.v1.Position; } else if (dot2 > dot3 && dot2 > dot1) { linedVertex = 2; linedVertexPos = face.v2.Position; } else { linedVertex = 3; linedVertexPos = face.v3.Position; } // Now find which of the intersection endpoints is nearest to that vertex. if ((linedVertexPos - startPos).Length > (linedVertexPos - endPos).Length) { return(BreakFaceInFive(face, startPos, endPos, linedVertex, facesFromSplit)); } else { return(BreakFaceInFive(face, endPos, startPos, linedVertex, facesFromSplit)); } } return(false); }
/// <summary> /// Face breaker for EDGE-EDGE-EDGE /// </summary> /// <param name="faceIndex">face index in the faces array</param> /// <param name="newPos1">new vertex position</param> /// <param name="newPos2">new vertex position</param> /// <param name="splitEdge">edge that will be split</param> private bool BreakFaceInThree(CsgFace face, Vector3 newPos1, Vector3 newPos2, int splitEdge, Stack <CsgFace> facesFromSplit) { // O // - - // - X // - * - // - * **X // -* **** - // X-----------O Vertex vertex1 = AddVertex(newPos1, FaceStatus.Boundary); Vertex vertex2 = AddVertex(newPos2, FaceStatus.Boundary); if (splitEdge == 1) // vertex 3 { bool willMakeExistingFace = (vertex1 == face.v1 && vertex2 == face.v2) || (vertex1 == face.v2 || vertex2 == face.v1); if (!willMakeExistingFace) { AddFaceFromSplit(face.v1, vertex1, face.v3, facesFromSplit); AddFaceFromSplit(vertex1, vertex2, face.v3, facesFromSplit); AddFaceFromSplit(vertex2, face.v2, face.v3, facesFromSplit); Faces.Remove(face); return(true); } } else if (splitEdge == 2) // vertex 1 { bool willMakeExistingFace = (vertex1 == face.v2 && vertex2 == face.v3) || (vertex1 == face.v3 || vertex2 == face.v2); if (!willMakeExistingFace) { AddFaceFromSplit(face.v2, vertex1, face.v1, facesFromSplit); AddFaceFromSplit(vertex1, vertex2, face.v1, facesFromSplit); AddFaceFromSplit(vertex2, face.v3, face.v1, facesFromSplit); Faces.Remove(face); return(true); } } else // vertex 2 { bool willMakeExistingFace = (vertex1 == face.v1 && vertex2 == face.v3) || (vertex1 == face.v3 || vertex2 == face.v1); if (!willMakeExistingFace) { AddFaceFromSplit(face.v3, vertex1, face.v2, facesFromSplit); AddFaceFromSplit(vertex1, vertex2, face.v2, facesFromSplit); AddFaceFromSplit(vertex2, face.v1, face.v2, facesFromSplit); Faces.Remove(face); return(true); } } if (vertex2 == vertices[vertices.Count - 1]) { vertices.RemoveAt(vertices.Count - 1); } if (vertex1 == vertices[vertices.Count - 1]) { vertices.RemoveAt(vertices.Count - 1); } return(false); }
/// <summary> /// Classifies the face based on the ray trace technique /// </summary> /// <param name="obj">object3d used to compute the face status</param> public void RayTraceClassify(CsgObject3D obj) { var random = new Random(); //creating a ray starting at the face baricenter going to the normal direction Ray ray = new Ray(center, Normal); //Line ray = new Line(GetNormal(), center); ray.PerturbDirection(random); bool success; double distance; Vector3 intersectionPoint; CsgFace closestFace = null; double closestDistance; do { success = true; closestDistance = Double.MaxValue; //for each face from the other solid... //foreach (Face face in obj.Faces.AllObjects()) obj.Faces.AlongRay(ray); foreach (var face in obj.Faces.QueryResults) { double hitDistance; bool front; //if ray intersects the plane... if (face.Plane.RayHitPlane(ray, out hitDistance, out front)) { double dotProduct = Vector3.Dot(face.Normal, ray.directionNormal); distance = hitDistance; intersectionPoint = ray.origin + ray.directionNormal * hitDistance; ray.maxDistanceToConsider = hitDistance; //if ray lies in plane... if (Math.Abs(distance) < EqualityTolerance && Math.Abs(dotProduct) < EqualityTolerance) { //disturb the ray in order to not lie into another plane ray.PerturbDirection(random); success = false; break; } //if ray starts in plane... if (Math.Abs(distance) < EqualityTolerance && Math.Abs(dotProduct) > EqualityTolerance) { //if ray intersects the face... if (face.ContainsPoint(intersectionPoint)) { //faces coincide closestFace = face; closestDistance = 0; break; } } //if ray intersects plane... else if (Math.Abs(dotProduct) > EqualityTolerance && distance > EqualityTolerance) { if (distance < closestDistance) { //if ray intersects the face; if (face.ContainsPoint(intersectionPoint)) { //this face is the closest face until now closestDistance = distance; closestFace = face; } } } } } } while (success == false); if (closestFace == null) { //none face found: outside face Status = FaceStatus.Outside; } else //face found: test dot product { double dotProduct = Vector3.Dot(closestFace.Normal, ray.directionNormal); //distance = 0: coplanar faces if (Math.Abs(closestDistance) < EqualityTolerance) { if (dotProduct > EqualityTolerance) { Status = FaceStatus.Same; } else if (dotProduct < -EqualityTolerance) { Status = FaceStatus.Opposite; } } else if (dotProduct > EqualityTolerance) { //dot product > 0 (same direction): inside face Status = FaceStatus.Inside; } else if (dotProduct < -EqualityTolerance) { //dot product < 0 (opposite direction): outside face Status = FaceStatus.Outside; } } }
/// <summary> /// Constructs a Segment based on elements obtained from the two planes relations /// </summary> /// <param name="line"></param> /// <param name="face"></param> /// <param name="side1"></param> /// <param name="side2"></param> /// <param name="side3"></param> public Segment(Line line, CsgFace face, PlaneSide side1, PlaneSide side2, PlaneSide side3) { this.line = line; index = 0; //VERTEX is an end if (side1 == PlaneSide.On) { SetVertex(face.v1); //other vertices on the same side - VERTEX-VERTEX VERTEX if (side2 == side3) { SetVertex(face.v1); } } //VERTEX is an end if (side2 == PlaneSide.On) { SetVertex(face.v2); //other vertices on the same side - VERTEX-VERTEX VERTEX if (side1 == side3) { SetVertex(face.v2); } } //VERTEX is an end if (side3 == PlaneSide.On) { SetVertex(face.v3); //other vertices on the same side - VERTEX-VERTEX VERTEX if (side1 == side2) { SetVertex(face.v3); } } //There are undefined ends - one or more edges cut the planes intersection line if (GetNumEndsSet() != 2) { //EDGE is an end if ((side1 == PlaneSide.Front && side2 == PlaneSide.Back) || (side1 == PlaneSide.Back && side2 == PlaneSide.Front)) { SetEdge(face.v1, face.v2); } //EDGE is an end if ((side2 == PlaneSide.Front && side3 == PlaneSide.Back) || (side2 == PlaneSide.Back && side3 == PlaneSide.Front)) { SetEdge(face.v2, face.v3); } //EDGE is an end if ((side3 == PlaneSide.Front && side1 == PlaneSide.Back) || (side3 == PlaneSide.Back && side1 == PlaneSide.Front)) { SetEdge(face.v3, face.v1); } } }