private static bool SearchForOutstandingVertex(Vertices hullArea, float hullTolerance, out Vector2 outstanding) { Vector2 outstandingResult = Vector2.Zero; bool found = false; if (hullArea.Count > 2) { int hullAreaLastPoint = hullArea.Count - 1; Vector2 tempVector1; Vector2 tempVector2 = hullArea[0]; Vector2 tempVector3 = hullArea[hullAreaLastPoint]; // Search between the first and last hull point. for (int i = 1; i < hullAreaLastPoint; i++) { tempVector1 = hullArea[i]; // Check if the distance is over the one that's tolerable. if ( LineTools.DistanceBetweenPointAndLineSegment(ref tempVector1, ref tempVector2, ref tempVector3) >= hullTolerance) { outstandingResult = hullArea[i]; found = true; break; } } } outstanding = outstandingResult; return(found); }
private static bool DistanceToHullAcceptable(PolygonCreationAssistance pca, Vertices polygon, Vector2 point, bool higherDetail) { if (polygon != null && polygon.Count > 2) { Vector2 edgeVertex2 = polygon[polygon.Count - 1]; Vector2 edgeVertex1; if (higherDetail) { for (int i = 0; i < polygon.Count; i++) { edgeVertex1 = polygon[i]; if (LineTools.DistanceBetweenPointAndLineSegment(ref point, ref edgeVertex1, ref edgeVertex2) <= pca.HullTolerance || LineTools.DistanceBetweenPointAndPoint(ref point, ref edgeVertex1) <= pca.HullTolerance) { return(false); } edgeVertex2 = polygon[i]; } return(true); } else { for (int i = 0; i < polygon.Count; i++) { edgeVertex1 = polygon[i]; if (LineTools.DistanceBetweenPointAndLineSegment(ref point, ref edgeVertex1, ref edgeVertex2) <= pca.HullTolerance) { return(false); } edgeVertex2 = polygon[i]; } return(true); } } return(false); }
/// <summary> /// Check for edge crossings /// </summary> /// <returns></returns> public bool IsSimple() { for (int i = 0; i < Count; ++i) { int iplus = (i + 1 > Count - 1) ? 0 : i + 1; Vector2 a1 = new Vector2(this[i].X, this[i].Y); Vector2 a2 = new Vector2(this[iplus].X, this[iplus].Y); for (int j = i + 1; j < Count; ++j) { int jplus = (j + 1 > Count - 1) ? 0 : j + 1; Vector2 b1 = new Vector2(this[j].X, this[j].Y); Vector2 b2 = new Vector2(this[jplus].X, this[jplus].Y); Vector2 temp; if (LineTools.LineIntersect2(a1, a2, b1, b2, out temp)) { return(false); } } } return(true); }
private static bool SplitPolygonEdge(Vertices polygon, EdgeAlignment edgeAlign, Vector2 coordInsideThePolygon, out int vertex1Index, out int vertex2Index) { List <CrossingEdgeInfo> edges; Vector2 slope; int nearestEdgeVertex1Index = 0; int nearestEdgeVertex2Index = 0; bool edgeFound = false; float shortestDistance = float.MaxValue; bool edgeCoordFound = false; Vector2 foundEdgeCoord = Vector2.Zero; vertex1Index = 0; vertex2Index = 0; switch (edgeAlign) { case EdgeAlignment.Vertical: edges = GetCrossingEdges(polygon, EdgeAlignment.Vertical, (int)coordInsideThePolygon.Y); foundEdgeCoord.Y = coordInsideThePolygon.Y; if (edges != null && edges.Count > 1 && edges.Count % 2 == 0) { float distance; for (int i = 0; i < edges.Count; i++) { if (edges[i].CrossingPoint.X < coordInsideThePolygon.X) { distance = coordInsideThePolygon.X - edges[i].CrossingPoint.X; if (distance < shortestDistance) { shortestDistance = distance; foundEdgeCoord.X = edges[i].CrossingPoint.X; edgeCoordFound = true; } } } if (edgeCoordFound) { shortestDistance = float.MaxValue; int edgeVertex2Index = polygon.Count - 1; int edgeVertex1Index; for (edgeVertex1Index = 0; edgeVertex1Index < polygon.Count; edgeVertex1Index++) { Vector2 tempVector1 = polygon[edgeVertex1Index]; Vector2 tempVector2 = polygon[edgeVertex2Index]; distance = LineTools.DistanceBetweenPointAndLineSegment(ref foundEdgeCoord, ref tempVector1, ref tempVector2); if (distance < shortestDistance) { shortestDistance = distance; nearestEdgeVertex1Index = edgeVertex1Index; nearestEdgeVertex2Index = edgeVertex2Index; edgeFound = true; } edgeVertex2Index = edgeVertex1Index; } if (edgeFound) { slope = polygon[nearestEdgeVertex2Index] - polygon[nearestEdgeVertex1Index]; slope.Normalize(); Vector2 tempVector = polygon[nearestEdgeVertex1Index]; distance = LineTools.DistanceBetweenPointAndPoint(ref tempVector, ref foundEdgeCoord); vertex1Index = nearestEdgeVertex1Index; vertex2Index = nearestEdgeVertex1Index + 1; polygon.Insert(nearestEdgeVertex1Index, distance * slope + polygon[vertex1Index]); polygon.Insert(nearestEdgeVertex1Index, distance * slope + polygon[vertex2Index]); return(true); } } } break; case EdgeAlignment.Horizontal: throw new Exception("EdgeAlignment.Horizontal isn't implemented yet. Sorry."); } return(false); }
// From Eric Jordan's convex decomposition library /// <summary> /// Trace the edge of a non-simple polygon and return a simple polygon. /// /// Method: /// Start at vertex with minimum y (pick maximum x one if there are two). /// We aim our "lastDir" vector at (1.0, 0) /// We look at the two rays going off from our start vertex, and follow whichever /// has the smallest angle (in -Pi . Pi) wrt lastDir ("rightest" turn) /// Loop until we hit starting vertex: /// We add our current vertex to the list. /// We check the seg from current vertex to next vertex for intersections /// - if no intersections, follow to next vertex and continue /// - if intersections, pick one with minimum distance /// - if more than one, pick one with "rightest" next point (two possibilities for each) /// </summary> /// <param name="verts">The vertices.</param> /// <returns></returns> public Vertices TraceEdge(Vertices verts) { PolyNode[] nodes = new PolyNode[verts.Count * verts.Count]; //overkill, but sufficient (order of mag. is right) int nNodes = 0; //Add base nodes (raw outline) for (int i = 0; i < verts.Count; ++i) { Vector2 pos = new Vector2(verts[i].X, verts[i].Y); nodes[i].Position = pos; ++nNodes; int iplus = (i == verts.Count - 1) ? 0 : i + 1; int iminus = (i == 0) ? verts.Count - 1 : i - 1; nodes[i].AddConnection(nodes[iplus]); nodes[i].AddConnection(nodes[iminus]); } //Process intersection nodes - horribly inefficient bool dirty = true; int counter = 0; while (dirty) { dirty = false; for (int i = 0; i < nNodes; ++i) { for (int j = 0; j < nodes[i].NConnected; ++j) { for (int k = 0; k < nNodes; ++k) { if (k == i || nodes[k] == nodes[i].Connected[j]) { continue; } for (int l = 0; l < nodes[k].NConnected; ++l) { if (nodes[k].Connected[l] == nodes[i].Connected[j] || nodes[k].Connected[l] == nodes[i]) { continue; } //Check intersection Vector2 intersectPt; bool crosses = LineTools.LineIntersect(nodes[i].Position, nodes[i].Connected[j].Position, nodes[k].Position, nodes[k].Connected[l].Position, out intersectPt); if (crosses) { dirty = true; //Destroy and re-hook connections at crossing point PolyNode connj = nodes[i].Connected[j]; PolyNode connl = nodes[k].Connected[l]; nodes[i].Connected[j].RemoveConnection(nodes[i]); nodes[i].RemoveConnection(connj); nodes[k].Connected[l].RemoveConnection(nodes[k]); nodes[k].RemoveConnection(connl); nodes[nNodes] = new PolyNode(intersectPt); nodes[nNodes].AddConnection(nodes[i]); nodes[i].AddConnection(nodes[nNodes]); nodes[nNodes].AddConnection(nodes[k]); nodes[k].AddConnection(nodes[nNodes]); nodes[nNodes].AddConnection(connj); connj.AddConnection(nodes[nNodes]); nodes[nNodes].AddConnection(connl); connl.AddConnection(nodes[nNodes]); ++nNodes; goto SkipOut; } } } } } SkipOut: ++counter; } //Collapse duplicate points bool foundDupe = true; int nActive = nNodes; while (foundDupe) { foundDupe = false; for (int i = 0; i < nNodes; ++i) { if (nodes[i].NConnected == 0) { continue; } for (int j = i + 1; j < nNodes; ++j) { if (nodes[j].NConnected == 0) { continue; } Vector2 diff = nodes[i].Position - nodes[j].Position; if (diff.LengthSquared() <= Settings.Epsilon * Settings.Epsilon) { if (nActive <= 3) { return(new Vertices()); } //printf("Found dupe, %d left\n",nActive); --nActive; foundDupe = true; PolyNode inode = nodes[i]; PolyNode jnode = nodes[j]; //Move all of j's connections to i, and orphan j int njConn = jnode.NConnected; for (int k = 0; k < njConn; ++k) { PolyNode knode = jnode.Connected[k]; Debug.Assert(knode != jnode); if (knode != inode) { inode.AddConnection(knode); knode.AddConnection(inode); } knode.RemoveConnection(jnode); } jnode.NConnected = 0; } } } } //Now walk the edge of the list //Find node with minimum y value (max x if equal) float minY = float.MaxValue; float maxX = -float.MaxValue; int minYIndex = -1; for (int i = 0; i < nNodes; ++i) { if (nodes[i].Position.Y < minY && nodes[i].NConnected > 1) { minY = nodes[i].Position.Y; minYIndex = i; maxX = nodes[i].Position.X; } else if (nodes[i].Position.Y == minY && nodes[i].Position.X > maxX && nodes[i].NConnected > 1) { minYIndex = i; maxX = nodes[i].Position.X; } } Vector2 origDir = new Vector2(1.0f, 0.0f); Vector2[] resultVecs = new Vector2[4 * nNodes]; // nodes may be visited more than once, unfortunately - change to growable array! int nResultVecs = 0; PolyNode currentNode = nodes[minYIndex]; PolyNode startNode = currentNode; Debug.Assert(currentNode.NConnected > 0); PolyNode nextNode = currentNode.GetRightestConnection(origDir); if (nextNode == null) { Vertices vertices = new Vertices(nResultVecs); for (int i = 0; i < nResultVecs; ++i) { vertices.Add(resultVecs[i]); } return(vertices); } // Borked, clean up our mess and return resultVecs[0] = startNode.Position; ++nResultVecs; while (nextNode != startNode) { if (nResultVecs > 4 * nNodes) { Debug.Assert(false); } resultVecs[nResultVecs++] = nextNode.Position; PolyNode oldNode = currentNode; currentNode = nextNode; nextNode = currentNode.GetRightestConnection(oldNode); if (nextNode == null) { Vertices vertices = new Vertices(nResultVecs); for (int i = 0; i < nResultVecs; ++i) { vertices.Add(resultVecs[i]); } return(vertices); } // There was a problem, so jump out of the loop and use whatever garbage we've generated so far } return(new Vertices()); }