Пример #1
0
        /// <summary>
        /// Returns ordered Lists of perimeter edges from a Mesh.
        /// There is no guarantee of directionality, only spatially sequential lines.
        /// </summary>
        /// <returns>
        /// A List of Lines.
        /// </returns>
        public static List <List <Line> > EdgesPerimeters(this Mesh mesh)
        {
            var edges = new List <Line>();

            mesh.Triangles.ToList().ForEach(t => edges.AddRange(t.Edges()));
            var pEdges     = edges.Where(e => e.Occurs(edges) == 1).ToList();
            var perimeters = new List <List <Line> >();

            while (pEdges.Count() > 0)
            {
                var edge = pEdges.First();
                pEdges = pEdges.Skip(1).ToList();
                var perimeter = new List <Line> {
                    edge
                };
                var connected = pEdges.Where(e => e.Start.IsAlmostEqualTo(edge.End) || e.End.IsAlmostEqualTo(edge.End)).ToList();
                while (connected.Count() > 0)
                {
                    pEdges.Remove(connected.First());
                    edge = new Line(edge.End, edge.End.FarthestFrom(connected.First().Points()));
                    perimeter.Add(edge);
                    connected = pEdges.Where(e => e.Start.IsAlmostEqualTo(edge.End) || e.End.IsAlmostEqualTo(edge.End)).ToList();
                }
                perimeters.Add(perimeter);
            }
            if (perimeters.Count == 1)
            {
                return(perimeters);
            }
            return(perimeters.OrderByDescending(p => Shaper.TotalLength(p)).ToList());
        }
Пример #2
0
        /// <summary>
        /// Returns the perpendicular distance from this Line to the supplied Vector3 point.
        /// </summary>
        /// <param name="point">Vector3 representing a point.</param>
        /// <returns>A double.</returns>
        public static double PerpendicularDistanceTo(this Line line, Vector3 point)
        {
            if (line.PointOnLine(point, true))
            {
                return(0.0);
            }
            var area = Math.Abs(Shaper.MakePolygon(new[] { line.Start, line.End, point }.ToList()).Area());

            return(area / (line.Length() * 0.5));
        }
Пример #3
0
        /// <summary>
        /// Returns a new Polygon rotated around a supplied Vector3 by the specified angle in degrees.
        /// </summary>
        /// <param name="pivot">The Vector3 base point of the rotation.</param>
        /// <param name="angle">The desired rotation angle in degrees.</param>
        /// <returns>
        /// A new Polygon.
        /// </returns>
        public static Polygon Rotate(this Polygon polygon, Vector3 pivot, double angle)
        {
            var theta    = angle * (Math.PI / 180);
            var vertices = new List <Vector3>();

            foreach (Vector3 vertex in polygon.Vertices)
            {
                var rX = (Math.Cos(theta) * (vertex.X - pivot.X)) - (Math.Sin(theta) * (vertex.Y - pivot.Y)) + pivot.X;
                var rY = (Math.Sin(theta) * (vertex.X - pivot.X)) + (Math.Cos(theta) * (vertex.Y - pivot.Y)) + pivot.Y;
                var rZ = vertex.Z;
                vertices.Add(new Vector3(rX, rY, rZ));
            }
            return(Shaper.MakePolygon(vertices));
        }
Пример #4
0
        /// <summary>
        /// Returns the List of Polygons that can merge with this Polygon.
        /// </summary>
        /// <param name="polygons">List of Polygons to test.</param>
        /// <returns>A List of Polygons that can be merged with this Polygon.</returns>
        public static List <Polygon> CanMerge(this Polygon polygon, List <Polygon> polygons)
        {
            var mrgPolygons = new List <Polygon>();

            foreach (var poly in polygons)
            {
                var polys = polygon.ToList();
                polys.Add(poly);
                if (Shaper.Merge(polys).Count == 1)
                {
                    mrgPolygons.Add(poly);
                }
            }
            return(mrgPolygons);
        }
Пример #5
0
        /// <summary>
        /// Attempts to scale up a Polygon until coming within the tolerance percentage of the target area.
        /// </summary>
        /// <param name="polygon">Polygon to scale.</param>
        /// <param name="area">Target area of the Polygon.</param>
        /// <param name="tolerance">Area total tolerance.</param>
        /// <param name="origin">Alignment location for final Polygon.</param>
        /// <param name="within">Polygon acting as a constraining outer boundary.</param>
        /// <param name="among">List of Polygons to avoid intersecting.</param>
        /// <returns>
        /// A new Polygon.
        /// </returns>
        public static Polygon ExpandToArea(this Polygon polygon, double area, double ratio,
                                           double tolerance = 0.1, Orient origin         = Orient.C,
                                           Polygon within   = null, List <Polygon> among = null)
        {
            if (polygon.IsClockWise())
            {
                polygon = polygon.Reversed();
            }
            if (Math.Abs(polygon.Area() - area) <= Math.Abs(tolerance * area))
            {
                return(polygon);
            }
            var     position = polygon.Compass().PointBy(origin);
            Polygon tryPoly  = Shaper.RectangleByArea(area, ratio);

            tryPoly = tryPoly.MoveFromTo(tryPoly.Compass().PointBy(origin), position);
            double tryArea = tryPoly.Area();

            do
            {
                var t = new Transform();
                t.Scale(tryArea / area, tryPoly.Compass().PointBy(origin));
                tryPoly = tryPoly.TransformedPolygon(t);
                if (within != null && tryPoly.Intersects(within))
                {
                    var tryPolys = within.Intersection(tryPoly);
                    if (tryPolys != null && tryPolys.Count > 0)
                    {
                        tryPoly = tryPolys.First();
                    }
                }
                if (among != null && tryPoly.Intersects(among))
                {
                    var tryPolys = Shaper.Differences(tryPoly.ToList(), among);
                    if (tryPolys != null && tryPolys.Count > 0)
                    {
                        tryPoly = tryPolys.First();
                    }
                }
                tryArea = tryPoly.Area();
            }while (!Shaper.NearEqual(tryPoly.Area(), area, tolerance * area) &&
                    !Shaper.NearEqual(tryPoly.Area(), tryArea, tolerance));
            return(tryPoly);
        }
Пример #6
0
        /// <summary>
        /// Creates the largest Polygon fitted to supplied intersecting Polygons.
        /// </summary>
        /// <param name="among">List of Polygons against which this Polygon must conform.</param>
        /// <returns>
        /// A new Polygon.
        /// </returns>
        public static Polygon FitAmong(this Polygon polygon, List <Polygon> among)
        {
            if (among == null || among.Count == 0)
            {
                return(polygon);
            }
            var polygons = Shaper.Differences(polygon.ToList(), among);

            if (polygons.Count == 0)
            {
                return(null);
            }
            polygon = polygons.OrderByDescending(p => Math.Abs(p.Area())).First();
            if (polygon.IsClockWise())
            {
                return(polygon.Reversed());
            }
            return(polygon);
        }
Пример #7
0
        /// <summary>
        /// Creates a new CCW Polygon of the same vertices with the start point now at the indexed Polygon vertex.
        /// </summary>
        /// <param name="start">The index of the point from which to start the new Polygon.</param>
        /// <returns>A new Polygon.</returns>
        public static Polygon RewindFrom(this Polygon polygon, int start)
        {
            var vertices = polygon.Vertices;

            if (start < 0 || start > vertices.Count - 1)
            {
                return(null);
            }
            var points = new List <Vector3>()
            {
                vertices[start]
            };
            var i = start + 1;

            while (i < vertices.Count)
            {
                points.Add(vertices[i % vertices.Count]);
                i++;
            }
            return(Shaper.MakePolygon(points));
        }
Пример #8
0
        /// <summary>
        /// Returns a List of Polygons derived from the Polygon's straight skeleton.
        /// </summary>
        /// <returns>A List of Polygons.</Line></returns>
        public static List <Polygon> Jigsaw(this Polygon polygon)
        {
            var vertices2d = new List <Vector2d>();

            foreach (var vertex in polygon.Vertices)
            {
                vertices2d.Add(new Vector2d(vertex.X, vertex.Y));
            }
            var skeleton = SkeletonBuilder.Build(vertices2d);
            var polygons = new List <Polygon>();

            foreach (var edgeResult in skeleton.Edges)
            {
                var vertices = new List <Vector3>();
                foreach (var vertex in edgeResult.Polygon)
                {
                    vertices.Add(new Vector3(vertex.X, vertex.Y, 0.0));
                }
                polygons.Add(Shaper.MakePolygon(vertices));
            }
            return(polygons.OrderBy(p => p.Centroid()).ToList());
        }
Пример #9
0
 /// <summary>
 /// Creates a Polygon with a reduced quantity of points tested against a deviation tolerance.
 /// </summary>
 /// <param name="tolerance">The deviation tolerance for inclusion in the final Vector3 List.</param>
 /// <returns>
 /// A new Polygon.
 /// </returns>
 public static Polygon Straighten(this Polygon polygon, double tolerance)
 {
     return(Shaper.MakePolygon(SimplifyNet.Straighten(polygon.Vertices.ToList(), tolerance)));
 }
Пример #10
0
 /// <summary>
 /// Reduces Polygon vertices.
 /// </summary>
 /// <param name="tolerance">The tolerated deviation to include a vertex.</param>
 /// <returns>A new Polyline.</returns>
 public static Polygon Simplify(this Polygon polygon, double minLength, double filletFactor = 1.0)
 {
     return(Shaper.MakePolygon(Shaper.Simplify(polygon.Vertices.ToList(), minLength, filletFactor)));
 }
Пример #11
0
 /// <summary>
 /// Reduces Polyline vertices.
 /// </summary>
 /// <param name="minLength">The tolerated deviation to include a vertex.</param>
 /// <returns>A new Polyline.</returns>
 public static Polyline Simplify(this Polyline polyline, double minLength, double filletFactor = 1.0)
 {
     return(new Polyline(Shaper.Simplify(polyline.Vertices.ToList(), minLength, filletFactor)));
 }
Пример #12
0
        /// <summary>
        /// Creates a rotated 2D grid of Vector3 points from the supplied Polygon, axis intervals, and angle.
        /// </summary>
        /// <param name="perimeter">Polygon boundary of the point grid.</param>
        /// <param name="xInterval">Spacing of the grid along the x-axis.</param>
        /// <param name="yInterval">Spacing of the grid along the y-axis.</param>
        /// <param name="angle">Rotation of the grid around the Polygon centroid.</param>
        /// <returns>
        /// A new CoordGrid.
        /// </returns>
        public CoordinateGrid(Polygon polygon, double xInterval = 1.0, double yInterval = 1.0, double angle = 0.0)
        {
            if (polygon == null)
            {
                return;
            }
            random    = new Random();
            Allocated = new List <Vector3>();
            Available = new List <Vector3>();
            Perimeter = Shaper.MakePolygon(polygon.Vertices.ToList());
            var centroid = polygon.Centroid();
            var box      = new CompassBox(polygon);
            var points   = new List <Vector3>();

            // Northeast quadrant
            var x = centroid.X + (xInterval * 0.5);
            var y = centroid.Y + (yInterval * 0.5);

            while (y <= box.NW.Y)
            {
                while (x <= box.SE.X)
                {
                    points.Add(new Vector3(x, y));
                    x += xInterval;
                }
                x  = centroid.X + (xInterval * 0.5);
                y += yInterval;
            }

            // Northwest quadrant
            x = centroid.X - (xInterval * 0.5);
            y = centroid.Y + (yInterval * 0.5);
            while (y <= box.NW.Y)
            {
                while (x >= box.SW.X)
                {
                    points.Add(new Vector3(x, y));
                    x -= xInterval;
                }
                x  = centroid.X - (xInterval * 0.5);
                y += yInterval;
            }

            // Southeast quadrant
            x = centroid.X + (xInterval * 0.5);
            y = centroid.Y - (yInterval * 0.5);
            while (y >= box.SW.Y)
            {
                while (x <= box.SE.X)
                {
                    points.Add(new Vector3(x, y));
                    x += xInterval;
                }
                x  = centroid.X + (xInterval * 0.5);
                y -= yInterval;
            }

            // Southwest quadrant
            x = centroid.X - (xInterval * 0.5);
            y = centroid.Y - (yInterval * 0.5);
            while (y >= box.SW.Y)
            {
                while (x >= box.SW.X)
                {
                    points.Add(new Vector3(x, y));
                    x -= xInterval;
                }
                x  = centroid.X - (xInterval * 0.5);
                y -= yInterval;
            }
            foreach (var pnt in points)
            {
                var point = pnt.Rotate(centroid, angle);
                if (polygon.Covers(point))
                {
                    Available.Add(point);
                }
            }
        }
Пример #13
0
 /// <summary>
 /// Returns a List of Lines representing the Arc divided into the specified quantity of segments.
 /// </summary>
 /// <param name="segments">Quantity of desired segments.</param>
 /// <returns>
 /// A List of Lines.
 /// </returns>
 public static List <Line> ToLines(this Arc arc, int segments)
 {
     return(Shaper.PointsToLines(arc.Divide(segments)));
 }