예제 #1
0
        private static void AddToMesh(this Csg.Polygon p, ref Mesh mesh)
        {
            // Polygons coming back from Csg can have an arbitrary number
            // of vertices. We need to retessellate the returned polygon.
            var tess = new Tess();

            tess.NoEmptyPolygons = true;

            tess.AddContour(p.Vertices.ToContourVertices());

            tess.Tessellate(WindingRule.Positive, LibTessDotNet.Double.ElementType.Polygons, 3);
            for (var i = 0; i < tess.ElementCount; i++)
            {
                var a = tess.Vertices[tess.Elements[i * 3]].Position.ToVector3();
                var b = tess.Vertices[tess.Elements[i * 3 + 1]].Position.ToVector3();
                var c = tess.Vertices[tess.Elements[i * 3 + 2]].Position.ToVector3();

                var uva = (Csg.Vector2D)tess.Vertices[tess.Elements[i * 3]].Data;
                var uvb = (Csg.Vector2D)tess.Vertices[tess.Elements[i * 3 + 1]].Data;
                var uvc = (Csg.Vector2D)tess.Vertices[tess.Elements[i * 3 + 2]].Data;

                var v1 = mesh.AddVertex(a, uva.ToUV());
                var v2 = mesh.AddVertex(b, uvb.ToUV());
                var v3 = mesh.AddVertex(c, uvc.ToUV());
                mesh.AddTriangle(v1, v2, v3);
            }
        }
예제 #2
0
        internal static Mesh ToMesh(this Tess tess,
                                    Transform transform = null,
                                    Color color         = default,
                                    Vector3 normal      = default)
        {
            var faceMesh = new Mesh();

            (Vector3 U, Vector3 V)basis = (default(Vector3), default(Vector3));

            for (var i = 0; i < tess.ElementCount; i++)
            {
                var a = tess.Vertices[tess.Elements[i * 3]].Position.ToVector3();
                var b = tess.Vertices[tess.Elements[i * 3 + 1]].Position.ToVector3();
                var c = tess.Vertices[tess.Elements[i * 3 + 2]].Position.ToVector3();

                if (transform != null)
                {
                    a = transform.OfPoint(a);
                    b = transform.OfPoint(b);
                    c = transform.OfPoint(c);
                }

                if (i == 0)
                {
                    // Calculate the texture space basis vectors
                    // from the first triangle. This is acceptable
                    // for planar faces.
                    // TODO: Update this when we support non-planar faces.
                    // https://gamedev.stackexchange.com/questions/172352/finding-texture-coordinates-for-plane
                    basis = Tessellation.Tessellation.ComputeBasisAndNormalForTriangle(a, b, c, out Vector3 naturalNormal);
                    if (normal == default)
                    {
                        normal = naturalNormal;
                    }
                }

                var v1 = faceMesh.AddVertex(a, new UV(basis.U.Dot(a), basis.V.Dot(a)), normal, color: color);
                var v2 = faceMesh.AddVertex(b, new UV(basis.U.Dot(b), basis.V.Dot(b)), normal, color: color);
                var v3 = faceMesh.AddVertex(c, new UV(basis.U.Dot(c), basis.V.Dot(c)), normal, color: color);

                faceMesh.AddTriangle(v1, v2, v3);
            }

            return(faceMesh);
        }
예제 #3
0
        /// <summary>
        /// Construct a mesh from an STL file.
        /// </summary>
        /// <param name="stlPath">The path to the STL file.</param>
        /// <param name="unit">The length unit used in the file.</param>
        /// <returns></returns>
        public static Mesh FromSTL(string stlPath, LengthUnit unit = LengthUnit.Millimeter)
        {
            List <Vertex> vertexCache = new List <Vertex>();
            var           mesh        = new Mesh();

            var conversion = Units.GetConversionToMeters(unit);

            using (var reader = new StreamReader(stlPath))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    line = line.TrimStart();

                    if (line.StartsWith("facet"))
                    {
                        vertexCache.Clear();
                    }

                    if (line.StartsWith("vertex"))
                    {
                        var splits = line.Split(' ');
                        var x      = double.Parse(splits[1]) * conversion;
                        var y      = double.Parse(splits[2]) * conversion;
                        var z      = double.Parse(splits[3]) * conversion;
                        var v      = new Vertex(new Vector3(x, y, z));
                        mesh.AddVertex(v);
                        vertexCache.Add(v);
                    }

                    if (line.StartsWith("endfacet"))
                    {
                        var t = new Triangle(vertexCache[0], vertexCache[1], vertexCache[2]);
                        if (!HasDuplicatedVertices(t, out _))
                        {
                            mesh.AddTriangle(t);
                        }
                    }
                }
            }
            mesh.ComputeNormals();
            return(mesh);
        }
예제 #4
0
        public static Elements.Geometry.Mesh ToMesh(this MeshData vMesh)
        {
            var mesh     = new Elements.Geometry.Mesh();
            var vertices = new List <Vertex>();

            for (int i = 0; i < vMesh.points.length; i++)
            {
                var pt     = (vMesh.points[i] as Array <double>).ToVector3();
                var normal = (vMesh.normals[i] as Array <double>).ToVector3();
                var vertex = new Vertex(pt, normal);
                vertices.Add(vertex);
                mesh.AddVertex(vertex);
            }
            Console.WriteLine(vertices.Count);
            for (int i = 0; i < vMesh.faces.length; i++)
            {
                var face = vMesh.faces[i] as Array <int>;
                mesh.AddTriangle(vertices[face[2]], vertices[face[1]], vertices[face[0]]);
            }
            return(mesh);
        }
예제 #5
0
        /// <summary>
        /// Generates a Roof from a DXF Polyline and supplied elevation and thickness values.
        /// </summary>
        /// <param name="model">The input model.</param>
        /// <param name="input">The arguments to the execution.</param>
        /// <returns>A RoofByDXFOutputs instance containing computed results and the model with any new elements.</returns>
        public static RoofByDXFOutputs Execute(Dictionary <string, Model> inputModels, RoofByDXFInputs input)
        {
            DxfFile dxfFile;

            using (FileStream fs = new FileStream(input.DXF.LocalFilePath, FileMode.Open))
            {
                dxfFile = DxfFile.Load(fs);
            }
            var polygons = new List <Polygon>();

            foreach (DxfEntity entity in dxfFile.Entities)
            {
                if (entity.EntityType != DxfEntityType.LwPolyline)
                {
                    continue;
                }
                var pline = (DxfLwPolyline)entity;
                if (pline.IsClosed == false)
                {
                    continue;
                }
                var vertices = pline.Vertices.ToList();
                var verts    = new List <Vector3>();
                vertices.ForEach(v => verts.Add(new Vector3(v.X, v.Y)));
                polygons.Add(new Polygon(verts));
            }
            if (polygons.Count == 0)
            {
                throw new ArgumentException("No LWPolylines found in DXF.");
            }
            var highPoint = input.RoofElevation + input.RoofThickness;

            polygons = polygons.OrderByDescending(p => Math.Abs(p.Area())).ToList();
            var polygon = polygons.First().IsClockWise() ? polygons.First().Reversed() : polygons.First();

            polygon = polygon.TransformedPolygon(new Transform(0.0, 0.0, highPoint));
            var underBoundary = polygon.TransformedPolygon(new Transform(0.0, 0.0, input.RoofThickness * -1.0));
            var ePoints       = polygon.Vertices.ToList();
            var uPoints       = underBoundary.Vertices.ToList();

            var topSide   = polygon.ToMesh(true);
            var underSide = underBoundary.ToMesh(false);

            var sideTriangles = new List <Elements.Geometry.Triangle>();

            for (var i = 0; i < ePoints.Count; i++)
            {
                sideTriangles.Add(new Elements.Geometry.Triangle(new Vertex(ePoints[i]),
                                                                 new Vertex(uPoints[i]),
                                                                 new Vertex(uPoints[(i + 1) % uPoints.Count])));
                sideTriangles.Add(new Elements.Geometry.Triangle(new Vertex(ePoints[i]),
                                                                 new Vertex(uPoints[(i + 1) % uPoints.Count]),
                                                                 new Vertex(ePoints[(i + 1) % ePoints.Count])));
            }


            // Create an aggregated list of Triangles representing the Roof envelope.
            var envTriangles = new List <Elements.Geometry.Triangle>();

            topSide.Triangles.ForEach(t => envTriangles.Add(t));
            underSide.Triangles.ForEach(t => envTriangles.Add(t));
            sideTriangles.ForEach(t => envTriangles.Add(t));

            // Create an aggregated list of Vertices representing the Roof envelope.
            var enVertices = new List <Vertex>();

            envTriangles.ForEach(t => enVertices.AddRange(t.Vertices));

            // Construct the roof envelope in Elements.Geometry.mesh form.
            var Envelope = new Elements.Geometry.Mesh();

            envTriangles.ForEach(t => Envelope.AddTriangle(t));
            enVertices.ForEach(v => Envelope.AddVertex(v));
            Envelope.ComputeNormals();

            // Construct serializable topside mesh
            var triangles = new List <triangles>();
            var indices   = new List <vertices>();
            var tsIV      = topSide.ToIndexedVertices();

            tsIV.triangles.ForEach(t => triangles.Add(new triangles(t)));
            tsIV.vertices.ForEach(v => indices.Add(new vertices(v.index, v.isBoundary, v.position)));
            var topside = new Elements.Mesh(triangles, indices);


            // Construct serializable underside mesh
            triangles.Clear();
            indices.Clear();
            var usIV = underSide.ToIndexedVertices();

            usIV.triangles.ForEach(t => triangles.Add(new triangles(t)));
            usIV.vertices.ForEach(v => indices.Add(new vertices(v.index, v.isBoundary, v.position)));
            var underside = new Elements.Mesh(triangles, indices);

            // Construct serializable envelope mesh
            triangles.Clear();
            indices.Clear();
            var enIV = Envelope.ToIndexedVertices();

            enIV.triangles.ForEach(t => triangles.Add(new triangles(t)));
            enIV.vertices.ForEach(v => indices.Add(new vertices(v.index, v.isBoundary, v.position)));
            var envelope = new Elements.Mesh(triangles, indices);

            var roof =
                new Roof(
                    envelope,
                    topside,
                    underside,
                    underBoundary,
                    input.RoofElevation,
                    highPoint,
                    input.RoofThickness,
                    polygon.Area(),
                    new Transform(),
                    BuiltInMaterials.Concrete,
                    null, false, Guid.NewGuid(), "Roof");
            var output = new RoofByDXFOutputs(polygon.Area());

            output.Model.AddElement(new MeshElement(Envelope, BuiltInMaterials.Concrete));
            output.Model.AddElement(roof);
            return(output);
        }
예제 #6
0
        /// <summary>
        /// A mesh sphere.
        /// </summary>
        /// <param name="radius">The radius of the sphere.</param>
        /// <param name="divisions">The number of tessellations of the sphere.</param>
        /// <returns>A mesh.</returns>
        public static Mesh Sphere(double radius, int divisions = 10)
        {
            if (divisions < 2)
            {
                throw new ArgumentException(nameof(divisions), "The number of divisions must be greater than 2.");
            }

            var arc      = new Arc(Vector3.Origin, radius, 0, 180).ToPolyline(divisions);
            var t        = new Transform();
            var vertices = new Vertex[divisions + 1, divisions + 1];
            var mesh     = new Mesh();
            var div      = 360.0 / divisions;

            for (var u = 0; u <= divisions; u++)
            {
                if (u > 0)
                {
                    t.Rotate(Vector3.XAxis, div);
                }

                for (var v = 1; v < divisions; v++)
                {
                    var pt = t.OfPoint(arc.Vertices[v]);

                    var vx = new Vertex(pt)
                    {
                        UV = new UV((double)v / (double)divisions, (double)u / (double)divisions)
                    };
                    vertices[u, v] = vx;
                    mesh.AddVertex(vx);

                    if (u > 0 && v > 1)
                    {
                        var a = vertices[u, v];
                        var b = vertices[u, v - 1];
                        var c = vertices[u - 1, v - 1];
                        var d = vertices[u - 1, v];

                        mesh.AddTriangle(a, b, c);
                        mesh.AddTriangle(a, c, d);
                    }
                }
            }

            var p1 = new Vertex(arc.Start)
            {
                UV = new UV(0, 0)
            };

            var p2 = new Vertex(arc.End)
            {
                UV = new UV(1, 1)
            };

            mesh.AddVertex(p1);
            mesh.AddVertex(p2);

            // Make the end caps separately to manage the singularity
            // at the poles. Attempting to do this in the algorithm above
            // will result in duplicate vertices for every arc section, which
            // is currently illegal in meshes.
            // TODO: This causes spiraling of the UV coordinates at the poles.
            for (var u = 1; u <= divisions; u++)
            {
                mesh.AddTriangle(p1, vertices[u - 1, 1], vertices[u, 1]);
                mesh.AddTriangle(p2, vertices[u, divisions - 1], vertices[u - 1, divisions - 1]);
            }

            mesh.ComputeNormals();

            return(mesh);
        }
예제 #7
0
        /// <summary>
        /// Creates a Roof from a supplied Polygon sketch and a supplied elevation.
        /// </summary>
        /// <param name="model">The input model.</param>
        /// <param name="input">The arguments to the execution.</param>
        /// <returns>A RoofBySketchOutputs instance containing computed results and the model with any new elements.</returns>
        public static RoofBySketchOutputs Execute(Dictionary <string, Model> inputModels, RoofBySketchInputs input)
        {
            var topSide = new Elements.Geometry.Mesh();
            var area    = 0.0;

            foreach (var triangle in input.Mesh.Triangles)
            {
                var a      = topSide.AddVertex(triangle.Vertices[0].Position);
                var b      = topSide.AddVertex(triangle.Vertices[1].Position);
                var c      = topSide.AddVertex(triangle.Vertices[2].Position);
                var triAng =
                    new Elements.Geometry.Triangle(a, b, c);
                topSide.AddTriangle(triAng);
                area += triAng.Area();
            }
            topSide.ComputeNormals();

            // Find the Mesh's lowest point and use the
            // roof thickness to the set the Roof's underside elevation.
            var vertices = input.Mesh.Vertices.ToList();

            vertices = vertices.OrderBy(v => v.Position.Z).ToList();
            var elevation = vertices.First().Position.Z - input.Thickness;

            // Find the topSide Mesh's perimeter points and use them to
            // construct a Mesh representing the underside of the Roof.
            var perimeter = topSide.EdgesPerimeters().First();
            var ePoints   = new List <Vector3>();

            perimeter.ForEach(e => ePoints.AddRange(e.Points()));
            ePoints = ePoints.Distinct().ToList();
            var uPoints = new List <Vector3>();

            ePoints.ForEach(p => uPoints.Add(new Vector3(p.X, p.Y, elevation)));
            var underBoundary = new Polygon(uPoints);
            var underSide     = underBoundary.ToMesh(false);

            // Use the topSide Mesh's edgePoints and the lower Mesh's underPoints
            // to construct a series of triangles forming the sides of the Roof.
            var sideTriangles = new List <Elements.Geometry.Triangle>();

            for (var i = 0; i < ePoints.Count; i++)
            {
                sideTriangles.Add(
                    new Elements.Geometry.Triangle(new Vertex(ePoints[i]),
                                                   new Vertex(uPoints[i]),
                                                   new Vertex(uPoints[(i + 1) % uPoints.Count])));
                sideTriangles.Add(
                    new Elements.Geometry.Triangle(new Vertex(ePoints[i]),
                                                   new Vertex(uPoints[(i + 1) % uPoints.Count]),
                                                   new Vertex(ePoints[(i + 1) % ePoints.Count])));
            }

            // Construct the roof envelope in Elements.Geometry.mesh form.
            // We add vertices individually by position so that we don't affect
            // the original vertices of hte individual faces
            var Envelope = new Elements.Geometry.Mesh();

            foreach (var t in topSide.Triangles)
            {
                var a = Envelope.AddVertex(t.Vertices[0].Position);
                var b = Envelope.AddVertex(t.Vertices[1].Position);
                var c = Envelope.AddVertex(t.Vertices[2].Position);

                Envelope.AddTriangle(new Triangle(a, b, c));
            }
            foreach (var t in underSide.Triangles)
            {
                var a = Envelope.AddVertex(t.Vertices[0].Position);
                var b = Envelope.AddVertex(t.Vertices[1].Position);
                var c = Envelope.AddVertex(t.Vertices[2].Position);

                Envelope.AddTriangle(new Triangle(a, b, c));
            }
            foreach (var t in sideTriangles)
            {
                var a = Envelope.AddVertex(t.Vertices[0].Position);
                var b = Envelope.AddVertex(t.Vertices[1].Position);
                var c = Envelope.AddVertex(t.Vertices[2].Position);

                Envelope.AddTriangle(new Triangle(a, b, c));
            }
            // enVertices.ToList().ForEach(v => Envelope.AddVertex(v));
            // envTriangles.ToList().ForEach(t => Envelope.AddTriangle(t));
            Envelope.ComputeNormals();

            //Record roof high point from topSide mesh.
            var highPoint = topSide.Points().OrderByDescending(p => p.Z).First().Z;

            // // code for when debugging the function.
            // var envelope = MakeEnvelope();
            // var topside = MakeTopside();
            // var underside = MakeUnderside();
            // var underBoundary = Polygon.Rectangle(20.0, 20.0);
            // var elevation = 10.0;
            // var highPoint = 15.0;
            // var area = 100.0;

            var roof =
                new Roof(
                    Envelope,
                    topSide,
                    underSide,
                    underBoundary,
                    elevation,
                    highPoint,
                    input.Thickness,
                    area,
                    new Transform(),
                    BuiltInMaterials.Concrete,
                    null, false, Guid.NewGuid(), "Roof");
            var output = new RoofBySketchOutputs(area);


            output.Model.AddElement(new MeshElement(Envelope, BuiltInMaterials.Concrete));
            output.Model.AddElement(roof);
            return(output);
        }