public void HalfEdgeGraphFromLinesBothWays() { Name = nameof(HalfEdgeGraphFromLinesBothWays); // not in order and inconsistently wound var lines = new List <Line> { new Line((0, 0), (10, 0)), new Line((10, 10), (5, 15)), new Line((10, 0), (10, 10)), new Line((0, 0), (0, 10)), new Line((0, 10), (5, 15)), }; var heg = HalfEdgeGraph2d.Construct(lines, true); var polygons = heg.Polygonize(); Assert.Equal(2, polygons.Count); Assert.Single(polygons.Where(p => p.Normal().Dot(Vector3.ZAxis) > 0)); }
public void HalfEdgeGraphFromLines() { Name = nameof(HalfEdgeGraphFromLines); // not in order, but clockwise-wound var lines = new List <Line> { new Line((0, 0), (10, 0)), new Line((10, 10), (5, 15)), new Line((10, 0), (10, 10)), new Line((0, 10), (0, 0)), new Line((5, 15), (0, 10)), }; var heg = HalfEdgeGraph2d.Construct(lines); var polygons = heg.Polygonize(); Assert.Single(polygons); Model.AddElement(polygons[0]); }
public void PolygonCleanupIssue() { Name = nameof(PolygonCleanupIssue); var rect = Polygon.Rectangle(10, 10); var splitters = Polygon.Rectangle(4, 15).Segments().Select(s => s.ToPolyline(1)); Model.AddElements(rect); var heg = HalfEdgeGraph2d.Construct(new[] { rect }, splitters); var polygons = heg.Polygonize(); Assert.Equal(3, polygons.Count); Assert.True(polygons.All(p => p.Segments().Count() == 4), "All polygons should be simple rectangles"); var rand = new Random(); foreach (var s in polygons) { Model.AddElement(new ModelCurve(s, rand.NextMaterial(), new Transform(0, 0, rand.NextDouble()))); } }
/// <summary> /// Intersect this solid with the provided plane. /// </summary> /// <param name="p">The plane of intersection.</param> /// <param name="result">A collection of polygons resulting /// from the intersection or null if there was no intersection.</param> /// <returns>True if an intersection occurred, otherwise false.</returns> public bool Intersects(Plane p, out List <Polygon> result) { var graphVertices = new List <Vector3>(); var graphEdges = new List <List <(int from, int to, int?tag)> >(); foreach (var f in this.Faces) { var facePlane = f.Value.Plane(); // If the face is coplanar, skip it. The edges of // the face also belong to adjacent faces and will // be included in their results. if (facePlane.IsCoplanar(p)) { continue; } var edgeResults = new List <Vector3>(); edgeResults.AddRange(IntersectLoop(f.Value.Outer, p)); if (f.Value.Inner != null) { foreach (var inner in f.Value.Inner) { edgeResults.AddRange(IntersectLoop(inner, p)); } } var d = facePlane.Normal.Cross(p.Normal).Unitized(); edgeResults.Sort(new DirectionComparer(d)); // Draw segments through the results and add to the // half edge graph. for (var j = 0; j < edgeResults.Count - 1; j += 2) { // Don't create zero-length edges. if (edgeResults[j].IsAlmostEqualTo(edgeResults[j + 1])) { continue; } var a = FindOrCreateGraphVertex(edgeResults[j], graphVertices, graphEdges); var b = FindOrCreateGraphVertex(edgeResults[j + 1], graphVertices, graphEdges); var e1 = (a, b, 0); var e2 = (b, a, 0); if (graphEdges[a].Contains(e1) || graphEdges[b].Contains(e2)) { continue; } else { graphEdges[a].Add(e1); } } } var heg = new HalfEdgeGraph2d() { Vertices = graphVertices, EdgesPerVertex = graphEdges }; try { var polys = heg.Polygonize(); if (polys == null || polys.Count == 0) { result = null; return(false); } result = polys; return(true); } catch (Exception ex) { // TODO: We could test for known failure modes, but the // iteration over the edge graph before attempting to // graph to identify these modes, is as expensive as // the graph attempt. // Known cases there the half edge graph will throw an // exception: // - Co-linear edges. // - Disconnected graphs. // - Graphs with one vertex. Console.WriteLine(ex.Message); result = null; return(false); } }