示例#1
0
        private static Mesh CreateBottom(Polygons path, double bottomHeight, double scaling)
        {
            var mesh = path.CreateVertexStorage(scaling).TriangulateFaces(zHeight: bottomHeight);

            mesh.ReverseFaces();
            return(mesh);
        }
示例#2
0
        public static Mesh Stitch(Polygons bottomLoop, double bottomHeight, Polygons topLoop, double topHeight, double scaling = 1000)
        {
            // only a bottom
            if (bottomLoop?.Count > 0 &&
                (topLoop == null || topLoop.Count == 0))
            {
                // if there is no top than we need to create a top
                return(CreateTop(bottomLoop, bottomHeight, scaling));
            }

            // only a top
            if ((bottomLoop == null || bottomLoop.Count == 0) &&
                topLoop.Count > 0)
            {
                // if there is no bottom than we need to create  bottom
                return(CreateBottom(topLoop, topHeight, scaling));
            }

            // simple bottom and top
            if (bottomLoop.Count == 1 &&
                topLoop.Count == 1 &&
                bottomLoop[0].Count == topLoop[0].Count)
            {
                var mesh = CreateSimpleWall(bottomLoop[0], bottomHeight * 1000, topLoop[0], topHeight * 1000);
                mesh.Transform(Matrix4X4.CreateScale(1 / scaling));
                return(mesh);
            }

            var all = new Polygons();

            all.AddRange(bottomLoop);
            all.AddRange(topLoop);
            all = all.GetCorrectedWinding();

            var bevelLoop = all.CreateVertexStorage().TriangulateFaces();

            for (var i = 0; i < bevelLoop.Vertices.Count; i++)
            {
                bevelLoop.Vertices[i] = bevelLoop.Vertices[i] + new Vector3Float(0, 0, 16);
            }

            return(bevelLoop);
        }
示例#3
0
        public static VertexStorage Offset(this IVertexSource a, double distance, JoinType joinType = JoinType.jtMiter, double scale = 1000)
        {
            var aPolys = a.CreatePolygons(scale);

            aPolys = aPolys.GetCorrectedWinding();

            var offseter = new ClipperOffset();

            offseter.AddPaths(aPolys, joinType, EndType.etClosedPolygon);
            var solution = new Polygons();

            offseter.Execute(ref solution, distance * scale);

            Clipper.CleanPolygons(solution);

            VertexStorage output = solution.CreateVertexStorage();

            output.Add(0, 0, ShapePath.FlagsAndCommand.Stop);

            return(output);
        }
        public static Mesh Revolve(IVertexSource source, int angleSteps = 30, double angleStart = 0, double angleEnd = MathHelper.Tau)
        {
            angleSteps = Math.Max(angleSteps, 3);
            angleStart = MathHelper.Range0ToTau(angleStart);
            angleEnd   = MathHelper.Range0ToTau(angleEnd);
            // convert to clipper polygons and scale so we can ensure good shapes
            Polygons polygons = source.CreatePolygons();
            // ensure good winding and consistent shapes
            // clip against x=0 left and right
            // mirror left material across the origin
            // union mirrored left with right material
            // convert the data back to PathStorage
            VertexStorage cleanedPath = polygons.CreateVertexStorage();

            Mesh mesh = new Mesh();

            var hasStartAndEndFaces = angleStart > 0.000001;

            hasStartAndEndFaces |= angleEnd < MathHelper.Tau - 0.000001;
            // check if we need to make closing faces
            if (hasStartAndEndFaces)
            {
                // make a face for the start
                CachedTesselator teselatedSource      = new CachedTesselator();
                Mesh             extrudedVertexSource = TriangulateFaces(source, teselatedSource);
                extrudedVertexSource.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4));
                extrudedVertexSource.Transform(Matrix4X4.CreateRotationZ(angleStart));
                mesh.CopyFaces(extrudedVertexSource);
            }

            // make the outside shell
            double angleDelta   = (angleEnd - angleStart) / angleSteps;
            double currentAngle = angleStart;

            if (!hasStartAndEndFaces)
            {
                angleSteps--;
            }

            for (int i = 0; i < angleSteps; i++)
            {
                AddRevolveStrip(cleanedPath, mesh, currentAngle, currentAngle + angleDelta);
                currentAngle += angleDelta;
            }

            if (!hasStartAndEndFaces)
            {
                if (((angleEnd - angleStart) < .0000001 ||
                     (angleEnd - MathHelper.Tau - angleStart) < .0000001) &&
                    (angleEnd - currentAngle) > .0000001)
                {
                    // make sure we close the shape exactly
                    AddRevolveStrip(cleanedPath, mesh, currentAngle, angleStart);
                }
            }
            else             // add the end face
            {
                // make a face for the end
                CachedTesselator teselatedSource      = new CachedTesselator();
                Mesh             extrudedVertexSource = TriangulateFaces(source, teselatedSource);
                extrudedVertexSource.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4));
                extrudedVertexSource.Transform(Matrix4X4.CreateRotationZ(currentAngle));
                extrudedVertexSource.ReverseFaceEdges();
                mesh.CopyFaces(extrudedVertexSource);
            }

            // return the completed mesh
            return(mesh);
        }
示例#5
0
        public static Mesh Extrude(this IVertexSource vertexSource, double zHeight)
        {
            Polygons polygons = vertexSource.CreatePolygons();

            // ensure good winding and consistent shapes
            polygons = polygons.GetCorrectedWinding();

            // convert the data back to PathStorage
            vertexSource = polygons.CreateVertexStorage();

            CachedTesselator teselatedSource = new CachedTesselator();
            Mesh             mesh            = vertexSource.TriangulateFaces(teselatedSource);
            int numIndicies = teselatedSource.IndicesCache.Count;

            mesh.Translate(new Vector3(0, 0, zHeight));

            // then the outside edge
            for (int i = 0; i < numIndicies; i += 3)
            {
                Vector2 v0 = teselatedSource.VerticesCache[teselatedSource.IndicesCache[i + 0].Index].Position;
                Vector2 v1 = teselatedSource.VerticesCache[teselatedSource.IndicesCache[i + 1].Index].Position;
                Vector2 v2 = teselatedSource.VerticesCache[teselatedSource.IndicesCache[i + 2].Index].Position;
                if (v0 == v1 || v1 == v2 || v2 == v0)
                {
                    continue;
                }

                var bottomVertex0 = new Vector3(v0, 0);
                var bottomVertex1 = new Vector3(v1, 0);
                var bottomVertex2 = new Vector3(v2, 0);

                var topVertex0 = new Vector3(v0, zHeight);
                var topVertex1 = new Vector3(v1, zHeight);
                var topVertex2 = new Vector3(v2, zHeight);

                if (teselatedSource.IndicesCache[i + 0].IsEdge)
                {
                    mesh.CreateFace(new Vector3[] { bottomVertex0, bottomVertex1, topVertex1, topVertex0 });
                }

                if (teselatedSource.IndicesCache[i + 1].IsEdge)
                {
                    mesh.CreateFace(new Vector3[] { bottomVertex1, bottomVertex2, topVertex2, topVertex1 });
                }

                if (teselatedSource.IndicesCache[i + 2].IsEdge)
                {
                    mesh.CreateFace(new Vector3[] { bottomVertex2, bottomVertex0, topVertex0, topVertex2 });
                }
            }

            // then the bottom
            for (int i = 0; i < numIndicies; i += 3)
            {
                Vector2 v0 = teselatedSource.VerticesCache[teselatedSource.IndicesCache[i + 0].Index].Position;
                Vector2 v1 = teselatedSource.VerticesCache[teselatedSource.IndicesCache[i + 1].Index].Position;
                Vector2 v2 = teselatedSource.VerticesCache[teselatedSource.IndicesCache[i + 2].Index].Position;
                if (v0 == v1 || v1 == v2 || v2 == v0)
                {
                    continue;
                }

                mesh.CreateFace(new Vector3[] { new Vector3(v2, 0), new Vector3(v1, 0), new Vector3(v0, 0) });
            }

            mesh.CleanAndMerge();

            return(mesh);
        }
        private void DoSmoothing(long maxDist, int interations)
        {
            bool closedPath = true;
            var  path       = this.Children.OfType <IPathObject>().FirstOrDefault();

            if (path == null)
            {
                // clear our existing data
                VertexSource = new VertexStorage();
                return;
            }
            var sourceVertices = path.VertexSource;

            var inputPolygons = sourceVertices.CreatePolygons();

            Polygons outputPolygons = new Polygons();

            foreach (Polygon inputPolygon in inputPolygons)
            {
                int  numVerts       = inputPolygon.Count;
                long maxDistSquared = maxDist * maxDist;

                var smoothedPositions = new Polygon(numVerts);
                foreach (IntPoint inputPosition in inputPolygon)
                {
                    smoothedPositions.Add(inputPosition);
                }

                for (int iteration = 0; iteration < interations; iteration++)
                {
                    var positionsThisPass = new Polygon(numVerts);
                    foreach (IntPoint inputPosition in smoothedPositions)
                    {
                        positionsThisPass.Add(inputPosition);
                    }

                    int startIndex = closedPath ? 0 : 1;
                    int endIndex   = closedPath ? numVerts : numVerts - 1;

                    for (int i = startIndex; i < endIndex; i++)
                    {
                        // wrap back to the previous index
                        IntPoint prev = positionsThisPass[(i + numVerts - 1) % numVerts];
                        IntPoint cur  = positionsThisPass[i];
                        IntPoint next = positionsThisPass[(i + 1) % numVerts];

                        IntPoint newPos = (prev + cur + next) / 3;
                        IntPoint delta  = newPos - inputPolygon[i];
                        if (delta.LengthSquared() > maxDistSquared)
                        {
                            delta  = delta.GetLength(maxDist);
                            newPos = inputPolygon[i] + delta;
                        }
                        smoothedPositions[i] = newPos;
                    }
                }

                outputPolygons.Add(smoothedPositions);

                outputPolygons = ClipperLib.Clipper.CleanPolygons(outputPolygons, Math.Max(maxDist / 10, 1.415));
            }

            VertexSource = outputPolygons.CreateVertexStorage();
        }
示例#7
0
 private static Mesh CreateTop(Polygons path, double topHeight, double scaling)
 {
     return(path.CreateVertexStorage(scaling).TriangulateFaces(zHeight: topHeight));
 }