public void ConvexHullFrom3DCloudAndNormal() { Name = nameof(ConvexHullFrom3DCloudAndNormal); var L = Polygon.L(2, 4, 1).TransformedPolygon(new Transform().Moved(3, 4)); var jitteredVertices = L.Vertices.ToList(); jitteredVertices[0] = new Transform().Moved(0, 0, 0.1).OfPoint(jitteredVertices[0]); jitteredVertices[1] = new Transform().Moved(0, 0, -0.1).OfPoint(jitteredVertices[1]); var flatHull = ConvexHull.FromPoints(L.Vertices); var jitteredHull = ConvexHull.FromPointsInPlane(jitteredVertices, Vector3.ZAxis); Assert.True(jitteredHull.IsAlmostEqualTo(flatHull), "Jittered flat hull doesn't match original hull."); // Simple transform allows simple polygon comparison for Assert. var simpleTransform = new Transform(Vector3.Origin, new Vector3(1, 0, 0).Unitized(), 0); var liftedPoints = jitteredVertices.Select(p => simpleTransform.OfPoint(p)); var liftedHull = ConvexHull.FromPointsInPlane(liftedPoints, Vector3.XAxis); Assert.True(liftedHull.IsAlmostEqualTo(flatHull.TransformedPolygon(simpleTransform)), "The lifted hull doesn't match the transformed flat hull."); // Complex transform can be used for visual inspection of the resulting frame. var complexTransform = new Transform(Vector3.Origin, new Vector3(1, 2, 0).Unitized(), 0); var complexLiftedPoints = jitteredVertices.Select(p => complexTransform.OfPoint(p)); var complexLiftedHull = ConvexHull.FromPointsInPlane(complexLiftedPoints, Vector3.XAxis); var complexliftedHull2 = ConvexHull.FromPointsInPlane(complexLiftedPoints, new Vector3(1, 1, 0));; this.Model.AddElement(L); this.Model.AddElement(new ModelCurve(flatHull, new Material("aqua", Colors.Aqua))); this.Model.AddElement(new ModelCurve(jitteredHull, new Material("cobalt", Colors.Cobalt))); this.Model.AddElements(CylinderAtPoints(complexLiftedPoints)); this.Model.AddElement(new ModelCurve(complexLiftedHull, new Material("cobalt", Colors.Cobalt))); this.Model.AddElement(new ModelCurve(complexliftedHull2, new Material("crimson", Colors.Crimson))); }
/// <summary> /// Extract polygons from a collection of elements. /// </summary> /// <param name="elements">The elements to get polygons from.</param> /// <param name="getDefaultPolygon">A function for extracting the default relevant polygon from an envelope. /// If this returns null, we'll use the 2D convex hull of the geometry of the element's representation </param> private static List <Polygon> ExtractPolygonsFromElements <T>(IEnumerable <T> elements, Func <T, Polygon> getDefaultPolygon) where T : GeometricElement { var polygons = new List <Polygon>(); foreach (var element in elements) { var polygon = getDefaultPolygon(element) ?? ConvexHull.FromPoints(element.Representation.SolidOperations.SelectMany(o => o.Solid.Vertices.Select(v => new Vector3(v.Value.Point.X, v.Value.Point.Y)))); polygons.Add(polygon); } return(polygons); }
public void ConvexHullOrthogonalWithDuplicateVertices() { var points = new List <Vector3>() { new Vector3(51.8160, 6.0960, 45.7200), new Vector3(0.0000, 6.0960, 45.7200), new Vector3(0.0000, 24.3840, 45.7200), new Vector3(51.8160, 24.3840, 45.7200), new Vector3(51.8160, 24.3840, 45.7200), new Vector3(51.8160, 6.0960, 45.7200) }; var hull = ConvexHull.FromPoints(points); Assert.Equal(4, hull.Segments().Length); }
public void ConvexHullAndBoundingRect() { Name = "Convex Hull"; var rand = new Random(); // fuzz test for (int test = 0; test < 50; test++) { var basePt = new Vector3((test % 5) * 12, (test - (test % 5)) / 5 * 12); var pts = new List <Vector3>(); for (int i = 0; i < 20; i++) { pts.Add(basePt + new Vector3(rand.NextDouble() * 10, rand.NextDouble() * 10)); } var modelPts = pts.Select(p => new ModelCurve(new Circle(p, 0.2))); var hull = ConvexHull.FromPoints(pts); var boundingRect = Polygon.FromAlignedBoundingBox2d(pts); Model.AddElements(modelPts); Model.AddElements(boundingRect); Model.AddElement(hull); } // handle collinear pts test var coPts = new List <Vector3> { new Vector3(0, 0), new Vector3(1, 0), new Vector3(2, 0), new Vector3(4, 0), new Vector3(10, 0), new Vector3(10, 5), new Vector3(10, 10) }; var coHull = ConvexHull.FromPoints(coPts); Assert.Equal(50, coHull.Area()); }
public static List <Envelope> SliceAtHeight(Envelope envelope, double cutHeight, Boolean showDebugGeometry) { var debugMaterial = new Material("DebugSolid", new Color(1, 0, 0, 1)); var plane = new Plane(new Vector3(0, 0, cutHeight), Vector3.ZAxis); var top = envelope.Elevation + envelope.Height; var envelopesForBlockage = new List <Envelope>(); var newUpperSolids = new List <Elements.Geometry.Solids.SolidOperation>(); Polygon slice = null; foreach (var solidOp in envelope.Representation.SolidOperations) { var intersections = new List <Vector3>(); var newUpperSolid = new Elements.Geometry.Solids.Solid(); foreach (var face in solidOp.Solid.Faces) { var polygon = face.Value.Outer.ToPolygon(); if (solidOp.LocalTransform != null) { polygon = (Polygon)polygon.Transformed(solidOp.LocalTransform); } if (envelope.Transform != null) { polygon = (Polygon)polygon.Transformed(envelope.Transform); } var faceIntersections = new List <Vector3>(); foreach (var segment in polygon.Segments()) { if (segment.Intersects(plane, out var intersection)) { intersections.Add(intersection); faceIntersections.Add(intersection); } } if (faceIntersections.Count == 0) { if (polygon.Centroid().Z > cutHeight) { newUpperSolid.AddFace(polygon); } } else if (faceIntersections.Count > 1) { faceIntersections = faceIntersections.OrderBy(p => p.X).ThenBy(p => p.Y).ToList(); var splitLine = new Polyline(faceIntersections); var splits = polygon.Split(splitLine); foreach (var split in splits) { if (split.Centroid().Z > cutHeight) { newUpperSolid.AddFace(split); } } } } if (intersections.Count >= 3) { slice = ConvexHull.FromPoints(intersections); slice = slice.Project(new Plane(new Vector3(), Vector3.ZAxis)); } else if (intersections.Count > 0) { Console.WriteLine($"Failed to intersect polygon for East Midtown: Found {intersections.Count} point"); } newUpperSolids.Add(new Elements.Geometry.Solids.ConstructedSolid(newUpperSolid)); } if (slice != null) { var extrude1 = new Elements.Geometry.Solids.Extrude(slice, cutHeight, Vector3.ZAxis, false); var rep1 = new Representation(new List <Elements.Geometry.Solids.SolidOperation>() { extrude1 }); var env1 = new Envelope(slice, 0, cutHeight, Vector3.ZAxis, 0, new Transform(), _debugMaterial, rep1, false, Guid.NewGuid(), ""); envelopesForBlockage.Add(env1); var rep2 = new Representation(newUpperSolids); var env2 = new Envelope(slice, 0, cutHeight, Vector3.ZAxis, 0, new Transform(), _debugMaterial, rep2, false, Guid.NewGuid(), ""); envelopesForBlockage.Add(env2); if (showDebugGeometry) { Model.AddElement(env1); Model.AddElement(env2); } } return(envelopesForBlockage); }