//--------------------------------------------------------------------------------------------------

        public static List <TopoDS_Face> Faces(this TopoDS_Shape shape, bool distinct = true)
        {
            Debug.Assert(shape != null);

            var faces = new List <TopoDS_Face>();

            var exp = new TopExp_Explorer(shape, TopAbs_ShapeEnum.TopAbs_FACE, TopAbs_ShapeEnum.TopAbs_SHAPE);

            while (exp.More())
            {
                var face = TopoDS.Face(exp.Current());
                exp.Next();

                if (distinct)
                {
                    var otherIndex = faces.FindIndex(e => e.IsSame(face));
                    if (otherIndex >= 0)
                    {
                        if (faces[otherIndex].Orientation() == TopAbs_Orientation.TopAbs_REVERSED &&
                            face.Orientation() == TopAbs_Orientation.TopAbs_FORWARD)
                        {
                            // Replace with forward face, this is prefered
                            faces[otherIndex] = face;
                        }

                        // Edge already present or replaced, skip adding
                        continue;
                    }
                }
                faces.Add(face);
            }
            return(faces);
        }
        //--------------------------------------------------------------------------------------------------

        public static List <TopoDS_Edge> Edges(this TopoDS_Shape shape, bool distinct = true)
        {
            var edges = new List <TopoDS_Edge>();

            var exp = new TopExp_Explorer(shape, TopAbs_ShapeEnum.TopAbs_EDGE, TopAbs_ShapeEnum.TopAbs_SHAPE);

            while (exp.More())
            {
                var edge = TopoDS.Edge(exp.Current());
                exp.Next();

                if (distinct)
                {
                    var otherEdgeIndex = edges.FindIndex(e => e.IsSame(edge));
                    if (otherEdgeIndex >= 0)
                    {
                        if (edges[otherEdgeIndex].Orientation() == TopAbs_Orientation.TopAbs_REVERSED &&
                            edge.Orientation() == TopAbs_Orientation.TopAbs_FORWARD)
                        {
                            // Replace with forward edge, this is prefered
                            edges[otherEdgeIndex] = edge;
                        }

                        // Edge already present or replaced, skip adding
                        continue;
                    }
                }

                edges.Add(edge);
            }
            return(edges);
        }
        /// <summary>
        /// triangulate using the opencascade's triangulation
        /// </summary>
        /// <param name="shape">input shape</param>
        /// <param name="deflection">parameter to define the maximum angle</param>
        /// <returns>a list of faces</returns>
        public List <Face> Triangulation(TopoDS_Shape shape, double deflection)
        {
            List <Face> faces = new List <Face>();

            BRepMesh.BRepMesh_IncrementalMesh im = new BRepMesh.BRepMesh_IncrementalMesh(shape, deflection); // 0.7 it controls the number of triangles
            im.Perform();
            if (im.IsDone())
            {
                for (TopExp_Explorer aFaceExplorer = new TopExp_Explorer(im.Shape(), TopAbs_ShapeEnum.TopAbs_FACE); aFaceExplorer.More(); aFaceExplorer.Next())
                {
                    TopoDS_Face face = TopoDS.TopoDS.ToFace(aFaceExplorer.Current());


                    TopLoc.TopLoc_Location L   = new TopLoc.TopLoc_Location();
                    Poly_Triangulation     tri = BRep.BRep_Tool.Triangulation(face, ref L);
                    bool isDone = true;

                    if (isDone)
                    {
                        Poly_Array1OfTriangle triangles = tri.Triangles();
                        TColgp_Array1OfPnt    nodes     = tri.Nodes();
                        for (int i = tri.Triangles().Lower(); i < tri.Triangles().Upper() + 1; i++)
                        {
                            Poly_Triangle triangle = triangles.Value(i);

                            int node1 = 0, node2 = 0, node3 = 0;
                            triangle.Get(ref node1, ref node2, ref node3);

                            gp_Pnt v1 = nodes.Value(node1);
                            gp_Pnt v2 = nodes.Value(node2);
                            gp_Pnt v3 = nodes.Value(node3);
                            // don't forget about face orientation :)
                            Face f = new Face(new List <gp_Pnt> {
                                v1, v2, v3
                            })
                            {
                                orientation = face.Orientation()
                            };
                            faces.Add(f);
                        }
                    }
                }
            }
            mesh = new MyMesh(faces);
            return(faces);
        }
        public static List <TopoDS_CompSolid> CompSolids(this TopoDS_Shape shape, bool distinct = true)
        {
            var compSolids = new List <TopoDS_CompSolid>();

            var exp = new TopExp_Explorer(shape, TopAbs_ShapeEnum.TopAbs_COMPSOLID, TopAbs_ShapeEnum.TopAbs_SHAPE);

            while (exp.More())
            {
                var compSolid = TopoDS.CompSolid(exp.Current());
                exp.Next();

                if (distinct)
                {
                    if (compSolids.Any(e => e.IsSame(compSolid)))
                    {
                        continue;
                    }
                }
                compSolids.Add(compSolid);
            }
            return(compSolids);
        }
        //--------------------------------------------------------------------------------------------------

        public static List <TopoDS_Shell> Shells(this TopoDS_Shape shape, bool distinct = true)
        {
            var shells = new List <TopoDS_Shell>();

            var exp = new TopExp_Explorer(shape, TopAbs_ShapeEnum.TopAbs_SHELL, TopAbs_ShapeEnum.TopAbs_SHAPE);

            while (exp.More())
            {
                var shell = TopoDS.Shell(exp.Current());
                exp.Next();

                if (distinct)
                {
                    if (shells.Any(e => e.IsSame(shell)))
                    {
                        continue;
                    }
                }
                shells.Add(shell);
            }
            return(shells);
        }
        //--------------------------------------------------------------------------------------------------

        public static List <TopoDS_Vertex> Vertices(this TopoDS_Shape shape, bool distinct = true)
        {
            var faces = new List <TopoDS_Vertex>();

            var exp = new TopExp_Explorer(shape, TopAbs_ShapeEnum.TopAbs_VERTEX, TopAbs_ShapeEnum.TopAbs_SHAPE);

            while (exp.More())
            {
                var vertex = TopoDS.Vertex(exp.Current());
                exp.Next();

                if (distinct)
                {
                    if (faces.Any(e => e.IsSame(vertex)))
                    {
                        continue;
                    }
                }
                faces.Add(vertex);
            }
            return(faces);
        }