Ejemplo n.º 1
0
        public TriangleNet.Mesh BuildMesh()
        {
            var polygon = BuildPolygon();

            var constraintOptions = new TriangleNet.Meshing.ConstraintOptions();

            constraintOptions.ConformingDelaunay = true;


            var qualityOptions = new TriangleNet.Meshing.QualityOptions();

            qualityOptions.MinimumAngle = 25;
            qualityOptions.MaximumAngle = 180;
            qualityOptions.MaximumArea  = 2500;

            var mesh = (TriangleNet.Mesh)TriangleNet.Geometry.ExtensionMethods.Triangulate(polygon.polygon, constraintOptions, qualityOptions);

            return(mesh);
        }
        public static List <Polyline> DelaunayTriangulation(this Polyline outerCurve, List <Polyline> innerCurves = null, double offsetDistance = -0.001, bool conformingDelaunay = true)
        {
            if (outerCurve == null)
            {
                BH.Engine.Base.Compute.RecordError("Cannot perform Delaunay Triangulation on an outer curve that is set to null.");
                return(new List <Polyline>());
            }

            // Create a zero length list if no holes input
            if (innerCurves == null)
            {
                innerCurves = new List <Polyline>();
            }

            double area = outerCurve.Area();

            for (int x = 0; x < innerCurves.Count; x++)
            {
                Polyline pLine = outerCurve.BooleanDifference(new List <Polyline> {
                    innerCurves[x]
                })[0];

                if (pLine.Area() != area)
                {
                    //The boolean difference returned a different polyline - offset this inner curve
                    innerCurves[x] = innerCurves[x].Offset(offsetDistance);
                }
            }

            // Get the transformation matrix
            Plane           plane           = outerCurve.IFitPlane();
            Vector          normal          = plane.Normal;
            List <Point>    vertices        = outerCurve.IDiscontinuityPoints();
            Point           refPoint        = vertices.Min();
            Point           refPointP       = BH.Engine.Geometry.Create.Point(refPoint.X, refPoint.Y, 0);
            Vector          zVector         = BH.Engine.Geometry.Create.Vector(0, 0, 1);
            Vector          rotationVector  = normal.CrossProduct(zVector).Normalise();
            double          rotationAngle   = normal.Angle(zVector);
            TransformMatrix transformMatrix = BH.Engine.Geometry.Create.RotationMatrix(vertices.Min(), rotationVector, rotationAngle);

            // Get the translation vector
            Vector translateVector = refPointP - refPoint;

            // Transform the original input curve/s
            Polyline        transformedCurve = Modify.Translate(outerCurve.Transform(transformMatrix), translateVector);
            List <Polyline> transformedHole  = new List <Polyline>();

            foreach (Polyline h in innerCurves)
            {
                if (h.IsCoplanar(outerCurve))
                {
                    transformedHole.Add(Modify.Translate(h.Transform(transformMatrix), translateVector));
                }
            }

            // Convert geometry to Triangle inputs
            TriangleNet.Geometry.Polygon       parentPolygon  = new TriangleNet.Geometry.Polygon();
            List <TriangleNet.Geometry.Vertex> parentVertices = new List <TriangleNet.Geometry.Vertex>();

            foreach (Point point in transformedCurve.IDiscontinuityPoints())
            {
                parentPolygon.Add(new TriangleNet.Geometry.Vertex(point.X, point.Y));
                parentVertices.Add(new TriangleNet.Geometry.Vertex(point.X, point.Y));
            }
            TriangleNet.Geometry.Contour parentContour = new TriangleNet.Geometry.Contour(parentVertices);
            parentPolygon.Add(parentContour);

            foreach (Polyline h in transformedHole)
            {
                List <TriangleNet.Geometry.Vertex> childVertices = new List <TriangleNet.Geometry.Vertex>();
                foreach (Point point in h.IDiscontinuityPoints())
                {
                    childVertices.Add(new TriangleNet.Geometry.Vertex(point.X, point.Y));
                }
                TriangleNet.Geometry.Contour childContour = new TriangleNet.Geometry.Contour(childVertices);
                Point childCentroid = h.PointInRegion();
                parentPolygon.Add(childContour, new TriangleNet.Geometry.Point(childCentroid.X, childCentroid.Y));
            }

            // Triangulate
            TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions()
            {
                ConformingDelaunay = conformingDelaunay,
            };
            TriangleNet.Meshing.QualityOptions quality = new TriangleNet.Meshing.QualityOptions()
            {
            };
            TriangleNet.Mesh mesh = (TriangleNet.Mesh)TriangleNet.Geometry.ExtensionMethods.Triangulate(parentPolygon, options, quality);

            // Convert triangulations back to BHoM geometry
            List <Polyline> translatedPolylines = new List <Polyline>();

            foreach (var face in mesh.Triangles)
            {
                // List points defining the triangle
                List <Point> pts = new List <Point>();
                pts.Add(BH.Engine.Geometry.Create.Point(face.GetVertex(0).X, face.GetVertex(0).Y));
                pts.Add(BH.Engine.Geometry.Create.Point(face.GetVertex(1).X, face.GetVertex(1).Y));
                pts.Add(BH.Engine.Geometry.Create.Point(face.GetVertex(2).X, face.GetVertex(2).Y));
                pts.Add(pts.First());
                translatedPolylines.Add(BH.Engine.Geometry.Create.Polyline(pts));
            }

            // Translate back to original plane
            List <Polyline> meshPolylines = new List <Polyline>();

            foreach (Polyline pl in translatedPolylines)
            {
                TransformMatrix matrixTransposed = transformMatrix.Invert();
                Polyline        meshPolyline     = pl.Translate(-translateVector).Transform(transformMatrix.Invert());
                meshPolylines.Add(meshPolyline);
            }

            return(meshPolylines);
        }
Ejemplo n.º 3
0
        // TODO Generalize Slice to be more than just a plane (Maybe a parametric surface or NURB?)
        // Implement with Binary Space Partitioning
        private Triangle[] PatchSlice(Plane Slice)    // this function triangulates the slicing plane so that the split parts are watertight
        {
            var PlanePts   = new HashSet <double3>(); // these are the points in the plane
            var PlaneTris  = new List <Triangle>();   // these will be holes or required triangles depending on the unit normal
            var PlaneLines = new HashSet <Line>();    // these are required edges in the surface triangulation

            for (int i = 0; i < Triangles.Length; i++)
            {
                var Tri  = Triangles[i];
                var LocA = Slice.AboveOrBelow(Tri.A);
                var LocB = Slice.AboveOrBelow(Tri.B);
                var LocC = Slice.AboveOrBelow(Tri.C);

                Tri.A = ToDouble3(ToFloat3(Tri.A));
                Tri.B = ToDouble3(ToFloat3(Tri.B));
                Tri.C = ToDouble3(ToFloat3(Tri.C));

                if (LocA == Location.On)
                {
                    PlanePts.Add(Tri.A);
                }


                if (LocB == Location.On)
                {
                    PlanePts.Add(Tri.B);
                }

                if (LocC == Location.On)
                {
                    PlanePts.Add(Tri.C);
                }

                if (LocA == Location.On && LocB == Location.On && LocC == Location.On)
                {
                    PlaneTris.Add(Tri);
                }
                else if (LocA == Location.On && LocB == Location.On)
                {
                    PlaneLines.Add(new Line(Tri.A, Tri.B));
                }
                else if (LocB == Location.On && LocC == Location.On)
                {
                    PlaneLines.Add(new Line(Tri.B, Tri.C));
                }
                else if (LocA == Location.On && LocB == Location.On)
                {
                    PlaneLines.Add(new Line(Tri.A, Tri.C));
                }
            }

            var Pts3D = PlanePts.ToArray();

            var Lines = PlaneLines.ToArray();

            var x_new = Pts3D[1] - Pts3D[0];

            x_new.Normalize(); // define the new x-axis as the vector between the  first two
            // coplanar points
            var z_new = Slice.UnitNormal;

            var Poly = new Polygon();

            double ZOffset = Slice.Transform(Pts3D[0], x_new).z;

            for (int i = 0; i < Pts3D.Length; i++)
            {
                var Pt_new     = Slice.Transform(Pts3D[i], x_new);
                var Vertex_new = new Vertex(Pt_new.x, Pt_new.y);
                Poly.Add(Vertex_new);
            }

            var EdgeSet = new HashSet <Edge>();

            for (int i = 0; i < Lines.Length; i++)
            {
                var PtA = Lines[i].A;
                var PtB = Lines[i].B;
                PtA = Slice.Transform(PtA, x_new);
                PtB = Slice.Transform(PtB, x_new);
                var P1 = new Vertex(PtA.x, PtA.y);
                var P2 = new Vertex(PtB.x, PtB.y);
                int I1 = Poly.Points.IndexOf(P1);
                int I2 = Poly.Points.IndexOf(P2);
                if (I1 == -1 || I2 == -1)
                {
                    Console.WriteLine("Bad Segment Found!");
                }

                var Edge = new Edge(Math.Min(I1, I2), Math.Max(I1, I2));
                EdgeSet.Add(Edge);
            }
            var PolyEdges = EdgeSet.ToArray();

            foreach (var item in PolyEdges)
            {
                Poly.Add(item);
            }
            //Poly = RemoveRedundantSegments(Poly.Segments, Poly.Points);

            bool Status = CheckWaterTightness(Poly.Segments, Poly.Points);

            TriangleNet.IO.TriangleWriter.WritePoly(Poly, "PolyTest.poly");

            if (Status == false)
            {
                Console.WriteLine("Warning, Inconsistent cross section detected!");
                //throw new Exception("STL File is not watertight!");
            }

            var qualityOptions = new TriangleNet.Meshing.QualityOptions();

            qualityOptions.MinimumAngle = 20;
            qualityOptions.MaximumAngle = 140;

            var myMesher = new TriangleNet.Meshing.GenericMesher();
            var myMesh   = (TriangleNet.Mesh)myMesher.Triangulate(Poly, qualityOptions); // Poly needs to be broken up into self contained singular regions

            // TODO:
            // How does this fair when the cross section is multiple separate regions adhering to Jordan Curve Theorem
            // Each region/ closed curve is a linked list.


            // FIXME: Write algorithm to break up seperate regions along the plane

            // Also account for holes being punched in the mesh (One side gets a hole, the mirror doesnt) when the cutting plane is along an interior surface

            // TODO Add back in unit normals to patch

            var Ans = new Triangle[myMesh.Triangles.Count];

            if (Ans.Length == 0)
            {
                throw new Exception("Patch Meshing Failure Detected!");
            }
            TriangleNet.IO.TriangleWriter.Write(myMesh, "MeshTest.ele");
            for (int i = 0; i < Ans.Length; i++)
            {
                var myTri = myMesh.Triangles.ElementAt(i);
                var P0    = myMesh.Vertices.ElementAt(myTri.P0);
                var P1    = myMesh.Vertices.ElementAt(myTri.P1);
                var P2    = myMesh.Vertices.ElementAt(myTri.P2);
                var PtA   = new double3(P0.X, P0.Y, ZOffset);
                var PtB   = new double3(P1.X, P1.Y, ZOffset);
                var PtC   = new double3(P2.X, P2.Y, ZOffset);
                PtA    = Slice.UnTransform(PtA, x_new); // map back to 3d
                PtB    = Slice.UnTransform(PtB, x_new);
                PtC    = Slice.UnTransform(PtC, x_new);
                Ans[i] = new Triangle(PtA, PtB, PtC);
            }
            return(Ans);
        }