Exemplo n.º 1
0
        /// <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);
        }
Exemplo n.º 2
0
        /// <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;
        }