public Polygon CreatePolygon() { Polygon result = new Polygon(); LinkedListNode <PointChain> current = closedPolygons.First; while (current != null) { SimpleClosedPath path = new SimpleClosedPath(result); LinkedListNode <Vector2> innerCurrent = current.Value.First; while (innerCurrent != null) { path.Add(innerCurrent.Value); innerCurrent = innerCurrent.Next; } result.Add(path); current = current.Next; } return(result); }
void UpdatePossibleBridges(SimpleClosedPath exterior, SimpleClosedPath mainHole) { possibleBridges.Clear(); foreach (Vector2 from in mainHole.Points()) { foreach (SimpleClosedPath hole in exterior.Holes()) { if (hole == mainHole) { continue; } foreach (Vector2 to in hole.Points()) { possibleBridges.Add(new ExtendedEdge(from, to)); } } foreach (Vector2 to in exterior.Points()) { possibleBridges.Add(new ExtendedEdge(from, to)); } } // possibleBridges.Sort(bridgeComparer); }
void Start() { Triangulator tri = new Triangulator(); // Vector2 p0 = new Vector2( 0.0f, 0.0f); // Vector2 p1 = new Vector2( 0.0f, 1.0f); // Vector2 p2 = new Vector2(-0.5f, 0.0f); // Debug.Log("Orientation of [" + p0 + p1 + "] [" + p2 + "] : " + Orientation(p0, p1, p2)); // p0 = new Vector2( 0.0f, 0.0f); // p1 = new Vector2( 0.0f, 1.0f); // p2 = new Vector2(+4.5f, -1.0f); // Debug.Log("Orientation of [" + p0 + p1 + "] [" + p2 + "] : " + Orientation(p0, p1, p2)); MartinezClipping clippingAlgo = new MartinezClipping(); Polygon subject = new Polygon(); Polygon clipper = new Polygon(); SimpleClosedPath subjectContour = new SimpleClosedPath(subject); SimpleClosedPath clipperContour = new SimpleClosedPath(clipper); foreach (Vector2 vertex in subjectVerts) { subjectContour.Add(vertex); } foreach (Vector2 vertex in clipperVerts) { clipperContour.Add(vertex); } subject.Add(subjectContour); clipper.Add(clipperContour); subject.ComputeHoles(); clipper.ComputeHoles(); clippingAlgo.subject = subject; clippingAlgo.clipper = clipper; Polygon result = clippingAlgo.Compute(operationType); result.ComputeHoles(); //result = tri.Simplify(result); polyRenderer.AddPolygon(subject, Color.red); polyRenderer.AddPolygon(clipper, Color.blue); polyRenderer.AddPolygon(result, Color.green); polyRenderer.AddEdges(clippingAlgo.DebugLines); }
bool IsBridgeValid(SimpleClosedPath exterior, ExtendedEdge bridge) { foreach (Edge e in exterior.AllEdges()) { List <Vector2> intersections = bridge.GetIntersectionsWith(e); if (intersections.Count > 0 && !e.HasEqualEndpoint(bridge)) { return(false); } } return(true); }
bool IsJoiningHole(SimpleClosedPath path, Edge joiningEdge) { foreach (Edge e in path.AllEdges()) { List <Vector2> intersections = joiningEdge.GetIntersectionsWith(e); if (intersections.Count > 0 && !e.HasEqualEndpoint(joiningEdge)) { return(false); } } return(true); }
public IEnumerable <Edge> AllEdges() { foreach (Edge e in OwnEdgesOnly()) { yield return(e); } for (int i = 0; i < holes.Count; ++i) { SimpleClosedPath hole = GetHole(i); foreach (Edge e in hole.OwnEdgesOnly()) { yield return(e); } } }
public SimpleClosedPath(SimpleClosedPath c, Polygon owner) { this.owner = owner; foreach (Vector2 p in c.points) { points.Add(new Vector2(p.x, p.y)); } foreach (int holeIndex in c.holes) { holes.Add(holeIndex); } isHole = c.isHole; alreadyCalled = c.alreadyCalled; isCounterClockwise = c.isCounterClockwise; }
/// <summary> /// Converts a polygon with holes to a polygon without holes /// </summary> public Polygon Simplify(Polygon inputPolygon) { Polygon result = new Polygon(); foreach (SimpleClosedPath exterior in inputPolygon.Exteriors()) { Vector2 firstPointOnExterior = exterior.GetPoint(0); SimpleClosedPath newExterior = new SimpleClosedPath(exterior, result); foreach (SimpleClosedPath hole in exterior.Holes()) { float minDistance = hole.Points().Min(p => Vector2.Distance(firstPointOnExterior, p)); Vector2 closestPointOnHole = hole.Points().Where(p => Vector2.Distance(firstPointOnExterior, p) == minDistance).FirstOrDefault(); Edge edge = new Edge(firstPointOnExterior, closestPointOnHole); if (IsJoiningHole(exterior, edge)) { newExterior = Join(exterior, hole, edge); } else // find correct pair : O(n³) where n equals max(points of exterior, points of interior) { foreach (Vector2 outside in exterior.Points()) { foreach (Vector2 inside in hole.Points()) { edge = new Edge(outside, inside); if (IsJoiningHole(exterior, edge)) // O(n) { newExterior = Join(newExterior, hole, edge); } } } } } // foreach hole result.Add(newExterior); } // foreach exterior return(result); //throw new InvalidOperationException("Can't find edges to join exteriors and interiors!"); }
SimpleClosedPath Join(SimpleClosedPath exterior, SimpleClosedPath hole, Edge edge) { connector.Clear(); connector.Add(new Edge(edge.To, edge.From)); foreach (Edge e in exterior.OwnEdgesOnly()) { connector.Add(e); } foreach (Edge e in hole.OwnEdgesOnly()) { connector.Add(e); } connector.Add(edge); return(connector.CreatePolygon().GetPath(0)); }
SimpleClosedPath Simplify(SimpleClosedPath exterior, Polygon newPolygon) { SimpleClosedPath result = new SimpleClosedPath(newPolygon); foreach (SimpleClosedPath hole in exterior.Holes()) { UpdatePossibleBridges(exterior, hole); while (!possibleBridges.IsEmpty()) { ExtendedEdge bridge = possibleBridges.ExtractFirst(); if (IsBridgeValid(exterior, bridge)) { //result.JoinByBridge(bridge); } } } return(result); }
void DrawPolygons() { float show = System.Convert.ToSingle(showGradients); float z = 3.0f; for (int polygonIndex = 0; polygonIndex < polygons.Count; ++polygonIndex) { if (!showOperands && polygonIndex <= 1) { continue; } if (!showResult && polygonIndex == 2) { continue; } Polygon polygon = polygons[polygonIndex]; Color polygonColor = colors[polygonIndex]; int depth = 0; float maxDepth = 3.0f; for (int pathIndex = 0; pathIndex < polygon.GetNumPaths(); ++pathIndex) { SimpleClosedPath path = polygon.GetPath(pathIndex); maxDepth = path.GetNumEdges() + 1; z -= 0.05f; //foreach (Edge edge in path.OwnEdgesOnly()) foreach (Edge edge in path.AllEdges()) { GL.Begin(GL.LINES); lineMat.SetPass(0); GL.Color(polygonColor * (1.0f - ((float)depth / maxDepth) * show)); GL.Vertex3(edge.From.x, edge.From.y, z); GL.Color(polygonColor * (1.0f - ((float)++depth / maxDepth) * show)); GL.Vertex3(edge.To.x, edge.To.y, z); GL.End(); } } } if (showResult || showOperands) { return; } z = 3.0f; for (int i = 0; i < edges.Count; ++i) { Edge edge = edges[i].Edge; Color color = !edges[i].InOut ? Color.white : Color.green; if (edges[i].Type == EdgeType.NON_CONTRIBUTING) { color = Color.red; } else if (edges[i].Type == EdgeType.SAME_TRANSITION) { color = Color.blue; } if (edges[i].Final) { color = edges[i].Sign; } Vector2 middle = Vector2.Lerp(edge.From, edge.To, 0.75f); z -= 0.05f; GL.Begin(GL.LINES); lineMat.SetPass(0); GL.Color(color); GL.Vertex3(edge.From.x, edge.From.y, z); GL.Vertex3(middle.x, middle.y, z); GL.Vertex3(middle.x, middle.y, z); GL.Color(edges[i].Final ? color : color * 0.25f); GL.Vertex3(edge.To.x, edge.To.y, z); GL.End(); } }
public void Add(SimpleClosedPath c) { paths.Add(c); }
// public int[] Triangulate(Polygon p) // { // Polygon shell = Simplify(p); // foreach (SimpleClosedPath path in shell) // { // } // } List <int> TriangulateSimpleClosedPath(SimpleClosedPath path) { List <Vector2> points = new List <Vector2>(); List <int> indices = new List <int>(); int n = points.Count; if (n < 3) { return(indices); } int[] V = new int[n]; // path needs to be counter clockwise int nv = n; int count = 2 * nv; for (int m = 0, v = nv - 1; nv > 2;) { if (count-- <= 0) { return(indices); } int u = v; if (nv <= u) { u = 0; } v = u + 1; if (nv <= v) { v = 0; } int w = v + 1; if (nv <= w) { w = 0; } if (Snip(u, v, w, nv, V, points)) { int a, b, c, s, t; a = V[u]; b = V[v]; c = V[w]; indices.Add(a); indices.Add(b); indices.Add(c); ++m; for (s = v, t = v + 1; t < nv; ++s, ++t) { V[s] = V[t]; } --nv; count = 2 * nv; } } return(indices); }