/// <summary> /// Creates a SimpleSweptSolidAnalyzer and computes the swept solid. /// </summary> /// <param name="faces">The faces of a solid.</param> /// <param name="normal">The normal of the reference plane that a path might lie on.</param> /// <returns>The analyzer.</returns> public static SimpleSweptSolidAnalyzer Create(ICollection <Face> faces, XYZ normal) { if (faces == null || faces.Count < 3) { throw new ArgumentException("Invalid faces.", "faces"); } if (normal == null) { throw new ArgumentNullException("normal"); } // find potential profile faces, their normal vectors must be orthogonal to the input normal List <PlanarFace> potentialSweepEndFaces = new List <PlanarFace>(); foreach (Face face in faces) { PlanarFace planarFace = face as PlanarFace; if (planarFace == null) { continue; } if (MathUtil.VectorsAreOrthogonal(normal, planarFace.Normal)) { potentialSweepEndFaces.Add(planarFace); } } if (potentialSweepEndFaces.Count < 2) { throw new InvalidOperationException("Can't find enough potential end faces."); } int i = 0; PlanarFace candidateProfileFace = null; // the potential profile face for the swept solid PlanarFace candidateProfileFace2 = null; Edge candidatePathEdge = null; bool foundCandidateFace = false; do { candidateProfileFace = potentialSweepEndFaces[i++]; // find edges on the candidate profile face and the side faces with the edges // later find edges on the other candidate profile face with same side faces // they will be used to compare if the edges are congruent // to make sure the two faces are the potential profile faces Dictionary <Face, Edge> sideFacesWithCandidateEdges = new Dictionary <Face, Edge>(); EdgeArrayArray candidateFaceEdgeLoops = candidateProfileFace.EdgeLoops; foreach (EdgeArray edgeArray in candidateFaceEdgeLoops) { foreach (Edge candidateEdge in edgeArray) { Face sideFace = candidateEdge.get_Face(0); if (sideFace == candidateProfileFace) { sideFace = candidateEdge.get_Face(1); } if (sideFacesWithCandidateEdges.ContainsKey(sideFace)) // should not happen { throw new InvalidOperationException("Failed"); } sideFacesWithCandidateEdges[sideFace] = candidateEdge; } } double candidateProfileFaceArea = candidateProfileFace.Area; foreach (PlanarFace theOtherCandidateFace in potentialSweepEndFaces) { if (theOtherCandidateFace.Equals(candidateProfileFace)) { continue; } if (!MathUtil.IsAlmostEqual(candidateProfileFaceArea, theOtherCandidateFace.Area)) { continue; } EdgeArrayArray theOtherCandidateFaceEdgeLoops = theOtherCandidateFace.EdgeLoops; bool failToFindTheOtherCandidateFace = false; Dictionary <Face, Edge> sideFacesWithTheOtherCandidateEdges = new Dictionary <Face, Edge>(); foreach (EdgeArray edgeArray in theOtherCandidateFaceEdgeLoops) { foreach (Edge theOtherCandidateEdge in edgeArray) { Face sideFace = theOtherCandidateEdge.get_Face(0); if (sideFace == theOtherCandidateFace) { sideFace = theOtherCandidateEdge.get_Face(1); } if (!sideFacesWithCandidateEdges.ContainsKey(sideFace)) // should already have { failToFindTheOtherCandidateFace = true; break; } if (sideFacesWithTheOtherCandidateEdges.ContainsKey(sideFace)) // should not happen { throw new InvalidOperationException("Failed"); } sideFacesWithTheOtherCandidateEdges[sideFace] = theOtherCandidateEdge; } } if (failToFindTheOtherCandidateFace) { continue; } if (sideFacesWithCandidateEdges.Count != sideFacesWithTheOtherCandidateEdges.Count) { continue; } // side faces with candidate profile face edges Dictionary <Face, List <Edge> > sideFacesWithEdgesDic = new Dictionary <Face, List <Edge> >(); foreach (Face sideFace in sideFacesWithCandidateEdges.Keys) { sideFacesWithEdgesDic[sideFace] = new List <Edge>(); sideFacesWithEdgesDic[sideFace].Add(sideFacesWithCandidateEdges[sideFace]); sideFacesWithEdgesDic[sideFace].Add(sideFacesWithTheOtherCandidateEdges[sideFace]); } if (!AreFacesSimpleCongruent(sideFacesWithEdgesDic)) { continue; } // find candidate path edges Dictionary <Face, List <Edge> > candidatePathEdgesWithFace = new Dictionary <Face, List <Edge> >(); foreach (KeyValuePair <Face, List <Edge> > sideFaceAndEdges in sideFacesWithEdgesDic) { List <Edge> pathEdges = FindCandidatePathEdge(sideFaceAndEdges.Key, sideFaceAndEdges.Value[0], sideFaceAndEdges.Value[1]); // maybe we found two faces of an opening or a recess on the swept solid, skip in this case if (pathEdges.Count < 2) { failToFindTheOtherCandidateFace = true; break; } candidatePathEdgesWithFace[sideFaceAndEdges.Key] = pathEdges; } if (failToFindTheOtherCandidateFace) { continue; } // check if these edges are congruent if (!AreEdgesSimpleCongruent(candidatePathEdgesWithFace)) { continue; } candidatePathEdge = candidatePathEdgesWithFace.Values.ElementAt(0).ElementAt(0); foundCandidateFace = true; candidateProfileFace2 = theOtherCandidateFace; break; } if (foundCandidateFace) { break; } } while (i < potentialSweepEndFaces.Count); SimpleSweptSolidAnalyzer simpleSweptSolidAnalyzer = null; if (foundCandidateFace) { simpleSweptSolidAnalyzer = new SimpleSweptSolidAnalyzer(); Curve pathCurve = candidatePathEdge.AsCurve(); XYZ endPoint0 = pathCurve.get_EndPoint(0); bool foundProfileFace = false; List <PlanarFace> profileFaces = new List <PlanarFace>(); profileFaces.Add(candidateProfileFace); profileFaces.Add(candidateProfileFace2); foreach (PlanarFace profileFace in profileFaces) { IntersectionResultArray intersectionResults; profileFace.Intersect(pathCurve, out intersectionResults); if (intersectionResults != null) { foreach (IntersectionResult intersectoinResult in intersectionResults) { XYZ intersectPoint = intersectoinResult.XYZPoint; if (intersectPoint.IsAlmostEqualTo(endPoint0)) { simpleSweptSolidAnalyzer.m_ProfileFace = profileFace; foundProfileFace = true; break; } } } if (foundProfileFace) { break; } } if (!foundProfileFace) { throw new InvalidOperationException("Failed to find profile face."); } // TODO: consider one profile face has an opening extrusion inside while the other does not List <Face> alignedFaces = FindAlignedFaces(profileFaces.ToList <Face>()); List <Face> unalignedFaces = new List <Face>(); foreach (Face face in faces) { if (profileFaces.Contains(face) || alignedFaces.Contains(face)) { continue; } unalignedFaces.Add(face); } simpleSweptSolidAnalyzer.m_UnalignedFaces = unalignedFaces; simpleSweptSolidAnalyzer.m_PathCurve = pathCurve; simpleSweptSolidAnalyzer.m_ReferencePlaneNormal = normal; } return(simpleSweptSolidAnalyzer); }
/// <summary> /// Creates a SimpleSweptSolidAnalyzer and computes the swept solid. /// </summary> /// <param name="faces">The faces of a solid.</param> /// <param name="normal">The normal of the reference plane that a path might lie on.</param> /// <returns>The analyzer.</returns> public static SimpleSweptSolidAnalyzer Create(ICollection<Face> faces, XYZ normal) { if (faces == null || faces.Count < 3) throw new ArgumentException("Invalid faces.", "faces"); if (normal == null) throw new ArgumentNullException("normal"); // find potential profile faces, their normal vectors must be orthogonal to the input normal List<PlanarFace> potentialSweepEndFaces = new List<PlanarFace>(); foreach (Face face in faces) { PlanarFace planarFace = face as PlanarFace; if (planarFace == null) continue; if (MathUtil.VectorsAreOrthogonal(normal, planarFace.Normal)) potentialSweepEndFaces.Add(planarFace); } if (potentialSweepEndFaces.Count < 2) throw new InvalidOperationException("Can't find enough potential end faces."); int i = 0; PlanarFace candidateProfileFace = null; // the potential profile face for the swept solid PlanarFace candidateProfileFace2 = null; Edge candidatePathEdge = null; bool foundCandidateFace = false; do { candidateProfileFace = potentialSweepEndFaces[i++]; // find edges on the candidate profile face and the side faces with the edges // later find edges on the other candidate profile face with same side faces // they will be used to compare if the edges are congruent // to make sure the two faces are the potential profile faces Dictionary<Face, Edge> sideFacesWithCandidateEdges = new Dictionary<Face, Edge>(); EdgeArrayArray candidateFaceEdgeLoops = candidateProfileFace.EdgeLoops; foreach (EdgeArray edgeArray in candidateFaceEdgeLoops) { foreach (Edge candidateEdge in edgeArray) { Face sideFace = candidateEdge.get_Face(0); if (sideFace == candidateProfileFace) sideFace = candidateEdge.get_Face(1); if (sideFacesWithCandidateEdges.ContainsKey(sideFace)) // should not happen throw new InvalidOperationException("Failed"); sideFacesWithCandidateEdges[sideFace] = candidateEdge; } } double candidateProfileFaceArea = candidateProfileFace.Area; foreach (PlanarFace theOtherCandidateFace in potentialSweepEndFaces) { if (theOtherCandidateFace.Equals(candidateProfileFace)) continue; if (!MathUtil.IsAlmostEqual(candidateProfileFaceArea, theOtherCandidateFace.Area)) continue; EdgeArrayArray theOtherCandidateFaceEdgeLoops = theOtherCandidateFace.EdgeLoops; bool failToFindTheOtherCandidateFace = false; Dictionary<Face, Edge> sideFacesWithTheOtherCandidateEdges = new Dictionary<Face, Edge>(); foreach (EdgeArray edgeArray in theOtherCandidateFaceEdgeLoops) { foreach (Edge theOtherCandidateEdge in edgeArray) { Face sideFace = theOtherCandidateEdge.get_Face(0); if (sideFace == theOtherCandidateFace) sideFace = theOtherCandidateEdge.get_Face(1); if (!sideFacesWithCandidateEdges.ContainsKey(sideFace)) // should already have { failToFindTheOtherCandidateFace = true; break; } if (sideFacesWithTheOtherCandidateEdges.ContainsKey(sideFace)) // should not happen throw new InvalidOperationException("Failed"); sideFacesWithTheOtherCandidateEdges[sideFace] = theOtherCandidateEdge; } } if (failToFindTheOtherCandidateFace) continue; if (sideFacesWithCandidateEdges.Count != sideFacesWithTheOtherCandidateEdges.Count) continue; // side faces with candidate profile face edges Dictionary<Face, List<Edge>> sideFacesWithEdgesDic = new Dictionary<Face, List<Edge>>(); foreach (Face sideFace in sideFacesWithCandidateEdges.Keys) { sideFacesWithEdgesDic[sideFace] = new List<Edge>(); sideFacesWithEdgesDic[sideFace].Add(sideFacesWithCandidateEdges[sideFace]); sideFacesWithEdgesDic[sideFace].Add(sideFacesWithTheOtherCandidateEdges[sideFace]); } if (!AreFacesSimpleCongruent(sideFacesWithEdgesDic)) continue; // find candidate path edges Dictionary<Face, List<Edge>> candidatePathEdgesWithFace = new Dictionary<Face, List<Edge>>(); foreach (KeyValuePair<Face, List<Edge>> sideFaceAndEdges in sideFacesWithEdgesDic) { List<Edge> pathEdges = FindCandidatePathEdge(sideFaceAndEdges.Key, sideFaceAndEdges.Value[0], sideFaceAndEdges.Value[1]); // maybe we found two faces of an opening or a recess on the swept solid, skip in this case if (pathEdges.Count < 2) { failToFindTheOtherCandidateFace = true; break; } candidatePathEdgesWithFace[sideFaceAndEdges.Key] = pathEdges; } if (failToFindTheOtherCandidateFace) continue; // check if these edges are congruent if (!AreEdgesSimpleCongruent(candidatePathEdgesWithFace)) continue; candidatePathEdge = candidatePathEdgesWithFace.Values.ElementAt(0).ElementAt(0); foundCandidateFace = true; candidateProfileFace2 = theOtherCandidateFace; break; } if (foundCandidateFace) break; } while (i < potentialSweepEndFaces.Count); SimpleSweptSolidAnalyzer simpleSweptSolidAnalyzer = null; if (foundCandidateFace) { simpleSweptSolidAnalyzer = new SimpleSweptSolidAnalyzer(); Curve pathCurve = candidatePathEdge.AsCurve(); XYZ endPoint0 = pathCurve.get_EndPoint(0); bool foundProfileFace = false; List<PlanarFace> profileFaces = new List<PlanarFace>(); profileFaces.Add(candidateProfileFace); profileFaces.Add(candidateProfileFace2); foreach (PlanarFace profileFace in profileFaces) { IntersectionResultArray intersectionResults; profileFace.Intersect(pathCurve, out intersectionResults); if (intersectionResults != null) { foreach (IntersectionResult intersectoinResult in intersectionResults) { XYZ intersectPoint = intersectoinResult.XYZPoint; if (intersectPoint.IsAlmostEqualTo(endPoint0)) { simpleSweptSolidAnalyzer.m_ProfileFace = profileFace; foundProfileFace = true; break; } } } if (foundProfileFace) break; } if (!foundProfileFace) throw new InvalidOperationException("Failed to find profile face."); // TODO: consider one profile face has an opening extrusion inside while the other does not List<Face> alignedFaces = FindAlignedFaces(profileFaces.ToList<Face>()); List<Face> unalignedFaces = new List<Face>(); foreach (Face face in faces) { if (profileFaces.Contains(face) || alignedFaces.Contains(face)) continue; unalignedFaces.Add(face); } simpleSweptSolidAnalyzer.m_UnalignedFaces = unalignedFaces; simpleSweptSolidAnalyzer.m_PathCurve = pathCurve; simpleSweptSolidAnalyzer.m_ReferencePlaneNormal = normal; } return simpleSweptSolidAnalyzer; }