public static List<Vertices> ConvexPartition(DetectedVertices vertices) { Polygon poly = new Polygon(); foreach (var vertex in vertices) poly.Points.Add(new TriangulationPoint(vertex.X, vertex.Y)); if (vertices.Holes != null) { foreach (var holeVertices in vertices.Holes) { Polygon hole = new Polygon(); foreach (var vertex in holeVertices) hole.Points.Add(new TriangulationPoint(vertex.X, vertex.Y)); poly.AddHole(hole); } } DTSweepContext tcx = new DTSweepContext(); tcx.PrepareTriangulation(poly); DTSweep.Triangulate(tcx); List<Vertices> results = new List<Vertices>(); foreach (DelaunayTriangle triangle in poly.Triangles) { Vertices v = new Vertices(); foreach (TriangulationPoint p in triangle.Points) { v.Add(new Vector2((float)p.X, (float)p.Y)); } results.Add(v); } return results; }
private List<float> SearchCrossingEdges(DetectedVertices polygon, int y) { if (polygon == null) throw new ArgumentNullException("polygon", "'polygon' can't be null."); if (polygon.Count < 3) throw new ArgumentException("'polygon.MainPolygon.Count' can't be less then 3."); List<float> result = SearchCrossingEdges((Vertices)polygon, y); if (polygon.Holes != null) { for (int i = 0; i < polygon.Holes.Count; i++) { result.AddRange(SearchCrossingEdges(polygon.Holes[i], y)); } } result.Sort(); return result; }
private bool InPolygon(DetectedVertices polygon, Vector2 point) { bool inPolygon = !DistanceToHullAcceptable(polygon, point, true); if (!inPolygon) { List<float> xCoords = SearchCrossingEdges(polygon, (int)point.Y); if (xCoords.Count > 0 && xCoords.Count % 2 == 0) { for (int i = 0; i < xCoords.Count; i += 2) { if (xCoords[i] <= point.X && xCoords[i + 1] >= point.X) return true; } } return false; } return true; }
private bool DistanceToHullAcceptable(DetectedVertices polygon, Vector2 point, bool higherDetail) { if (polygon == null) throw new ArgumentNullException("polygon", "'polygon' can't be null."); if (polygon.Count < 3) throw new ArgumentException("'polygon.MainPolygon.Count' can't be less then 3."); // Check the distance to main polygon. if (DistanceToHullAcceptable((Vertices)polygon, point, higherDetail)) { if (polygon.Holes != null) { for (int i = 0; i < polygon.Holes.Count; i++) { // If there is one distance not acceptable then return false. if (!DistanceToHullAcceptable(polygon.Holes[i], point, higherDetail)) return false; } } // All distances are larger then _hullTolerance. return true; } // Default to false. return false; }
public List<DetectedVertices> DetectVertices() { #region Check TextureConverter setup. if (_data == null) throw new Exception( "'_data' can't be null. You have to use SetTextureData(uint[] data, int width) before calling this method."); if (_data.Length < 4) throw new Exception( "'_data' length can't be less then 4. Your texture must be at least 2 x 2 pixels in size. " + "You have to use SetTextureData(uint[] data, int width) before calling this method."); if (_width < 2) throw new Exception( "'_width' can't be less then 2. Your texture must be at least 2 x 2 pixels in size. " + "You have to use SetTextureData(uint[] data, int width) before calling this method."); if (_data.Length % _width != 0) throw new Exception( "'_width' has an invalid value. You have to use SetTextureData(uint[] data, int width) before calling this method."); #endregion List<DetectedVertices> detectedPolygons = new List<DetectedVertices>(); DetectedVertices polygon; Vertices holePolygon; Vector2? holeEntrance = null; Vector2? polygonEntrance = null; List<Vector2> blackList = new List<Vector2>(); bool searchOn; do { if (detectedPolygons.Count == 0) { // First pass / single polygon polygon = new DetectedVertices(CreateSimplePolygon(Vector2.Zero, Vector2.Zero)); if (polygon.Count > 2) polygonEntrance = GetTopMostVertex(polygon); } else if (polygonEntrance.HasValue) { // Multi pass / multiple polygons polygon = new DetectedVertices(CreateSimplePolygon( polygonEntrance.Value, new Vector2(polygonEntrance.Value.X - 1f, polygonEntrance.Value.Y))); } else break; searchOn = false; if (polygon.Count > 2) { if (_holeDetection) { do { holeEntrance = SearchHoleEntrance(polygon, holeEntrance); if (holeEntrance.HasValue) { if (!blackList.Contains(holeEntrance.Value)) { blackList.Add(holeEntrance.Value); holePolygon = CreateSimplePolygon(holeEntrance.Value, new Vector2(holeEntrance.Value.X + 1, holeEntrance.Value.Y)); if (holePolygon != null && holePolygon.Count > 2) { switch (_polygonDetectionType) { case VerticesDetectionType.Integrated: // Add first hole polygon vertex to close the hole polygon. holePolygon.Add(holePolygon[0]); int vertex1Index, vertex2Index; if (SplitPolygonEdge(polygon, holeEntrance.Value, out vertex1Index, out vertex2Index)) polygon.InsertRange(vertex2Index, holePolygon); break; case VerticesDetectionType.Separated: if (polygon.Holes == null) polygon.Holes = new List<Vertices>(); polygon.Holes.Add(holePolygon); break; } } } else break; } else break; } while (true); } detectedPolygons.Add(polygon); } if (_multipartDetection || polygon.Count <= 2) { if (SearchNextHullEntrance(detectedPolygons, polygonEntrance.Value, out polygonEntrance)) searchOn = true; } } while (searchOn); if (detectedPolygons == null || (detectedPolygons != null && detectedPolygons.Count == 0)) throw new Exception("Couldn't detect any vertices."); // Post processing. if (PolygonDetectionType == VerticesDetectionType.Separated) // Only when VerticesDetectionType.Separated? -> Recheck. ApplyTriangulationCompatibleWinding(ref detectedPolygons); if (_pixelOffsetOptimization) ApplyPixelOffsetOptimization(ref detectedPolygons); if (_transform != Matrix.Identity) ApplyTransform(ref detectedPolygons); return detectedPolygons; }