private static bool InPolygon(PolygonCreationAssistance pca, Vertices polygon, Vector2 point) { bool inPolygon = !DistanceToHullAcceptable(pca, polygon, point, true); if (!inPolygon) { List <CrossingEdgeInfo> edges = GetCrossingEdges(polygon, EdgeAlignment.Vertical, (int)point.Y); if (edges.Count > 0 && edges.Count % 2 == 0) { for (int i = 0; i < edges.Count; i += 2) { if (edges[i].CrossingPoint.X <= point.X && edges[i + 1].CrossingPoint.X >= point.X) { return(true); } } return(false); } return(false); } return(true); }
/// <summary> /// Detects the vertices of the supplied texture data. /// </summary> /// <param name="data">The texture data.</param> /// <param name="width">The texture width.</param> /// <param name="height">The texture height.</param> /// <returns></returns> public static Vertices DetectVertices(uint[] data, int width, int height) { PolygonCreationAssistance pca = new PolygonCreationAssistance(data, width, height); List <Vertices> verts = DetectVertices(ref pca); return(verts[0]); }
private static bool GetNextHullEntrance(PolygonCreationAssistance pca, Vector2 start, out Vector2?entrance) { // Search for first solid pixel. int size = pca.Height * pca.Width; int x; bool foundTransparent = false; for (int i = (int)start.X + (int)start.Y * pca.Width; i <= size; i++) { if (pca.IsSolid(i)) { if (foundTransparent) { x = i % pca.Width; entrance = new Vector2(x, (i - x) / (float)pca.Width); return(true); } } else { foundTransparent = true; } } // If there are no solid pixels. entrance = null; return(false); }
private static bool GetNextHullPoint(PolygonCreationAssistance pca, ref Vector2 last, ref Vector2 current, out Vector2 next) { int x; int y; int indexOfFirstPixelToCheck = GetIndexOfFirstPixelToCheck(ref last, ref current); int indexOfPixelToCheck; const int pixelsToCheck = 8; // _closePixels.Length; for (int i = 0; i < pixelsToCheck; i++) { indexOfPixelToCheck = (indexOfFirstPixelToCheck + i) % pixelsToCheck; x = (int)current.X + ClosePixels[indexOfPixelToCheck, 0]; y = (int)current.Y + ClosePixels[indexOfPixelToCheck, 1]; if (x >= 0 && x < pca.Width && y >= 0 && y <= pca.Height) { if (pca.IsSolid(x, y)) //todo { next = new Vector2(x, y); return(true); } } } next = Vector2.Zero; return(false); }
/// <summary> /// Detects the vertices of the supplied texture data. /// </summary> /// <param name="data">The texture data.</param> /// <param name="width">The texture width.</param> /// <param name="height">The texture height.</param> /// <param name="holeDetection">if set to <c>true</c> it will perform hole detection.</param> /// <param name="hullTolerance">The hull tolerance.</param> /// <param name="alphaTolerance">The alpha tolerance.</param> /// <param name="multiPartDetection">if set to <c>true</c> it will perform multi part detection.</param> /// <returns></returns> public static List <Vertices> DetectVertices(uint[] data, int width, int height, float hullTolerance, byte alphaTolerance, bool multiPartDetection, bool holeDetection) { PolygonCreationAssistance pca = new PolygonCreationAssistance(data, width, height); pca.HullTolerance = hullTolerance; pca.AlphaTolerance = alphaTolerance; pca.MultipartDetection = multiPartDetection; pca.HoleDetection = holeDetection; return(DetectVertices(ref pca)); }
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); }
private static bool IsNearPixel(PolygonCreationAssistance pca, ref Vector2 current, ref Vector2 near) { for (int i = 0; i < 8; i++) { int x = (int)current.X + ClosePixels[i, 0]; int y = (int)current.Y + ClosePixels[i, 1]; if (x >= 0 && x <= pca.Width && y >= 0 && y <= pca.Height) { if (x == (int)near.X && y == (int)near.Y) { return(true); } } } return(false); }
private static bool GetHullEntrance(PolygonCreationAssistance pca, out Vector2 entrance) { // Search for first solid pixel. for (int y = 0; y <= pca.Height; y++) { for (int x = 0; x <= pca.Width; x++) { if (pca.IsSolid(x, y)) { entrance = new Vector2(x, y); return(true); } } } // If there are no solid pixels. entrance = Vector2.Zero; return(false); }
private static bool SearchNearPixels(PolygonCreationAssistance pca, bool searchingForSolidPixel, ref Vector2 current, out Vector2 foundPixel) { for (int i = 0; i < 8; i++) { int x = (int)current.X + ClosePixels[i, 0]; int y = (int)current.Y + ClosePixels[i, 1]; if (!searchingForSolidPixel ^ pca.IsSolid(x, y)) { foundPixel = new Vector2(x, y); return(true); } } // Nothing found. foundPixel = Vector2.Zero; return(false); }
private static bool IsNearPixel(PolygonCreationAssistance pca, ref Vector2 current, ref Vector2 near) { for (int i = 0; i < 8; i++) { int x = (int) current.X + ClosePixels[i, 0]; int y = (int) current.Y + ClosePixels[i, 1]; if (x >= 0 && x <= pca.Width && y >= 0 && y <= pca.Height) { if (x == (int) near.X && y == (int) near.Y) { return true; } } } return false; }
private static Vertices CreateSimplePolygon(PolygonCreationAssistance pca, Vector2 entrance, Vector2 last) { bool entranceFound = false; bool endOfHull = false; Vertices polygon = new Vertices(32); Vertices hullArea = new Vertices(32); Vertices endOfHullArea = new Vertices(32); Vector2 current = Vector2.Zero; #region Entrance check // Get the entrance point. //todo: alle möglichkeiten testen if (entrance == Vector2.Zero || !pca.InBounds(ref entrance)) { entranceFound = GetHullEntrance(pca, out entrance); if (entranceFound) { current = new Vector2(entrance.X - 1f, entrance.Y); } } else { if (pca.IsSolid(ref entrance)) { if (IsNearPixel(pca, ref entrance, ref last)) { current = last; entranceFound = true; } else { Vector2 temp; if (SearchNearPixels(pca, false, ref entrance, out temp)) { current = temp; entranceFound = true; } else { entranceFound = false; } } } } #endregion if (entranceFound) { polygon.Add(entrance); hullArea.Add(entrance); Vector2 next = entrance; do { // Search in the pre vision list for an outstanding point. Vector2 outstanding; if (SearchForOutstandingVertex(hullArea, pca.HullTolerance, out outstanding)) { if (endOfHull) { // We have found the next pixel, but is it on the last bit of the hull? if (endOfHullArea.Contains(outstanding)) { // Indeed. polygon.Add(outstanding); } // That's enough, quit. break; } // Add it and remove all vertices that don't matter anymore // (all the vertices before the outstanding). polygon.Add(outstanding); hullArea.RemoveRange(0, hullArea.IndexOf(outstanding)); } // Last point gets current and current gets next. Our little spider is moving forward on the hull ;). last = current; current = next; // Get the next point on hull. if (GetNextHullPoint(pca, ref last, ref current, out next)) { // Add the vertex to a hull pre vision list. hullArea.Add(next); } else { // Quit break; } if (next == entrance && !endOfHull) { // It's the last bit of the hull, search on and exit at next found vertex. endOfHull = true; endOfHullArea.AddRange(hullArea); } } while (true); } return polygon; }
private static List<Vertices> DetectVertices(ref PolygonCreationAssistance pca) { List<Vertices> polygons = new List<Vertices>(); Vertices polygon; Vertices holePolygon; Vector2? holeEntrance = null; Vector2? polygonEntrance = null; List<Vector2> blackList = new List<Vector2>(); // Check the array you just got. Debug.Assert(pca.IsValid(), "Sizes don't match: Color array must contain texture width * texture height elements."); bool searchOn; do { if (polygons.Count == 0) { polygon = CreateSimplePolygon(pca, Vector2.Zero, Vector2.Zero); if (polygon != null && polygon.Count > 2) { polygonEntrance = GetTopMostVertex(polygon); } } else if (polygonEntrance.HasValue) { polygon = CreateSimplePolygon(pca, polygonEntrance.Value, new Vector2(polygonEntrance.Value.X - 1f, polygonEntrance.Value.Y)); } else { break; } searchOn = false; if (polygon != null && polygon.Count > 2) { if (pca.HoleDetection) { do { holeEntrance = GetHoleHullEntrance(pca, polygon, holeEntrance); if (holeEntrance.HasValue) { if (!blackList.Contains(holeEntrance.Value)) { blackList.Add(holeEntrance.Value); holePolygon = CreateSimplePolygon(pca, holeEntrance.Value, new Vector2(holeEntrance.Value.X + 1, holeEntrance.Value.Y)); if (holePolygon != null && holePolygon.Count > 2) { holePolygon.Add(holePolygon[0]); int vertex2Index; int vertex1Index; if (SplitPolygonEdge(polygon, EdgeAlignment.Vertical, holeEntrance.Value, out vertex1Index, out vertex2Index)) { polygon.InsertRange(vertex2Index, holePolygon); } } } else { break; } } else { break; } } while (true); } polygons.Add(polygon); if (pca.MultipartDetection) { // 1: 95 / 151 // 2: 232 / 252 // while (GetNextHullEntrance(pca, polygonEntrance.Value, out polygonEntrance)) { bool inPolygon = false; for (int i = 0; i < polygons.Count; i++) { polygon = polygons[i]; if (InPolygon(pca, polygon, polygonEntrance.Value)) { inPolygon = true; break; } } if (!inPolygon) { searchOn = true; break; } } } } } while (searchOn); return polygons; }
private static Vertices CreateSimplePolygon(PolygonCreationAssistance pca, Vector2 entrance, Vector2 last) { bool entranceFound = false; bool endOfHull = false; Vertices polygon = new Vertices(32); Vertices hullArea = new Vertices(32); Vertices endOfHullArea = new Vertices(32); Vector2 current = Vector2.Zero; #region Entrance check // Get the entrance point. //todo: alle möglichkeiten testen if (entrance == Vector2.Zero || !pca.InBounds(ref entrance)) { entranceFound = GetHullEntrance(pca, out entrance); if (entranceFound) { current = new Vector2(entrance.X - 1f, entrance.Y); } } else { if (pca.IsSolid(ref entrance)) { if (IsNearPixel(pca, ref entrance, ref last)) { current = last; entranceFound = true; } else { Vector2 temp; if (SearchNearPixels(pca, false, ref entrance, out temp)) { current = temp; entranceFound = true; } else { entranceFound = false; } } } } #endregion if (entranceFound) { polygon.Add(entrance); hullArea.Add(entrance); Vector2 next = entrance; do { // Search in the pre vision list for an outstanding point. Vector2 outstanding; if (SearchForOutstandingVertex(hullArea, pca.HullTolerance, out outstanding)) { if (endOfHull) { // We have found the next pixel, but is it on the last bit of the hull? if (endOfHullArea.Contains(outstanding)) { // Indeed. polygon.Add(outstanding); } // That's enough, quit. break; } // Add it and remove all vertices that don't matter anymore // (all the vertices before the outstanding). polygon.Add(outstanding); hullArea.RemoveRange(0, hullArea.IndexOf(outstanding)); } // Last point gets current and current gets next. Our little spider is moving forward on the hull ;). last = current; current = next; // Get the next point on hull. if (GetNextHullPoint(pca, ref last, ref current, out next)) { // Add the vertex to a hull pre vision list. hullArea.Add(next); } else { // Quit break; } if (next == entrance && !endOfHull) { // It's the last bit of the hull, search on and exit at next found vertex. endOfHull = true; endOfHullArea.AddRange(hullArea); } } while (true); } return(polygon); }
private static Vector2? GetHoleHullEntrance(PolygonCreationAssistance pca, Vertices polygon, Vector2? startVertex) { List<CrossingEdgeInfo> edges; Vector2? entrance; int startLine; int endLine; int lastSolid = 0; bool foundSolid; bool foundTransparent; if (polygon != null && polygon.Count > 0) { if (startVertex.HasValue) { startLine = (int) startVertex.Value.Y; } else { startLine = (int) GetTopMostCoord(polygon); } endLine = (int) GetBottomMostCoord(polygon); if (startLine > 0 && startLine < pca.Height && endLine > 0 && endLine < pca.Height) { // go from top to bottom of the polygon for (int y = startLine; y <= endLine; y += pca.HoleDetectionLineStepSize) { // get x-coord of every polygon edge which crosses y edges = GetCrossingEdges(polygon, EdgeAlignment.Vertical, y); // we need an even number of crossing edges if (edges.Count > 1 && edges.Count%2 == 0) { for (int i = 0; i < edges.Count; i += 2) { foundSolid = false; foundTransparent = false; for (int x = (int) edges[i].CrossingPoint.X; x <= (int) edges[i + 1].CrossingPoint.X; x++) { if (pca.IsSolid(x, y)) { if (!foundTransparent) { foundSolid = true; lastSolid = x; } if (foundSolid && foundTransparent) { entrance = new Vector2(lastSolid, y); if (DistanceToHullAcceptable(pca, polygon, entrance.Value, true)) { return entrance; } entrance = null; break; } } else { if (foundSolid) { foundTransparent = true; } } } } } } } } return null; }
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> /// Detects the vertices of the supplied texture data. /// </summary> /// <param name="data">The texture data.</param> /// <param name="width">The texture width.</param> /// <param name="height">The texture height.</param> /// <param name="holeDetection">if set to <c>true</c> it will perform hole detection.</param> /// <param name="hullTolerance">The hull tolerance.</param> /// <param name="alphaTolerance">The alpha tolerance.</param> /// <param name="multiPartDetection">if set to <c>true</c> it will perform multi part detection.</param> /// <returns></returns> public static List<Vertices> DetectVertices(uint[] data, int width, int height, float hullTolerance, byte alphaTolerance, bool multiPartDetection, bool holeDetection) { PolygonCreationAssistance pca = new PolygonCreationAssistance(data, width, height); pca.HullTolerance = hullTolerance; pca.AlphaTolerance = alphaTolerance; pca.MultipartDetection = multiPartDetection; pca.HoleDetection = holeDetection; return DetectVertices(ref pca); }
private static bool GetHullEntrance(PolygonCreationAssistance pca, out Vector2 entrance) { // Search for first solid pixel. for (int y = 0; y <= pca.Height; y++) { for (int x = 0; x <= pca.Width; x++) { if (pca.IsSolid(x, y)) { entrance = new Vector2(x, y); return true; } } } // If there are no solid pixels. entrance = Vector2.Zero; return false; }
private static bool GetNextHullEntrance(PolygonCreationAssistance pca, Vector2 start, out Vector2? entrance) { // Search for first solid pixel. int size = pca.Height*pca.Width; int x; bool foundTransparent = false; for (int i = (int) start.X + (int) start.Y*pca.Width; i <= size; i++) { if (pca.IsSolid(i)) { if (foundTransparent) { x = i%pca.Width; entrance = new Vector2(x, (i - x)/(float) pca.Width); return true; } } else { foundTransparent = true; } } // If there are no solid pixels. entrance = null; return false; }
private static bool InPolygon(PolygonCreationAssistance pca, Vertices polygon, Vector2 point) { bool inPolygon = !DistanceToHullAcceptable(pca, polygon, point, true); if (!inPolygon) { List<CrossingEdgeInfo> edges = GetCrossingEdges(polygon, EdgeAlignment.Vertical, (int) point.Y); if (edges.Count > 0 && edges.Count%2 == 0) { for (int i = 0; i < edges.Count; i += 2) { if (edges[i].CrossingPoint.X <= point.X && edges[i + 1].CrossingPoint.X >= point.X) { return true; } } return false; } return false; } return true; }
private static bool GetNextHullPoint(PolygonCreationAssistance pca, ref Vector2 last, ref Vector2 current, out Vector2 next) { int x; int y; int indexOfFirstPixelToCheck = GetIndexOfFirstPixelToCheck(ref last, ref current); int indexOfPixelToCheck; const int pixelsToCheck = 8; // _closePixels.Length; for (int i = 0; i < pixelsToCheck; i++) { indexOfPixelToCheck = (indexOfFirstPixelToCheck + i)%pixelsToCheck; x = (int) current.X + ClosePixels[indexOfPixelToCheck, 0]; y = (int) current.Y + ClosePixels[indexOfPixelToCheck, 1]; if (x >= 0 && x < pca.Width && y >= 0 && y <= pca.Height) { if (pca.IsSolid(x, y)) //todo { next = new Vector2(x, y); return true; } } } next = Vector2.Zero; return false; }
private static bool SearchNearPixels(PolygonCreationAssistance pca, bool searchingForSolidPixel, ref Vector2 current, out Vector2 foundPixel) { for (int i = 0; i < 8; i++) { int x = (int) current.X + ClosePixels[i, 0]; int y = (int) current.Y + ClosePixels[i, 1]; if (!searchingForSolidPixel ^ pca.IsSolid(x, y)) { foundPixel = new Vector2(x, y); return true; } } // Nothing found. foundPixel = Vector2.Zero; return false; }
private static Vector2?GetHoleHullEntrance(PolygonCreationAssistance pca, Vertices polygon, Vector2?startVertex) { List <CrossingEdgeInfo> edges; Vector2?entrance; int startLine; int endLine; int lastSolid = 0; bool foundSolid; bool foundTransparent; if (polygon != null && polygon.Count > 0) { if (startVertex.HasValue) { startLine = (int)startVertex.Value.Y; } else { startLine = (int)GetTopMostCoord(polygon); } endLine = (int)GetBottomMostCoord(polygon); if (startLine > 0 && startLine < pca.Height && endLine > 0 && endLine < pca.Height) { // go from top to bottom of the polygon for (int y = startLine; y <= endLine; y += pca.HoleDetectionLineStepSize) { // get x-coord of every polygon edge which crosses y edges = GetCrossingEdges(polygon, EdgeAlignment.Vertical, y); // we need an even number of crossing edges if (edges.Count > 1 && edges.Count % 2 == 0) { for (int i = 0; i < edges.Count; i += 2) { foundSolid = false; foundTransparent = false; for (int x = (int)edges[i].CrossingPoint.X; x <= (int)edges[i + 1].CrossingPoint.X; x++) { if (pca.IsSolid(x, y)) { if (!foundTransparent) { foundSolid = true; lastSolid = x; } if (foundSolid && foundTransparent) { entrance = new Vector2(lastSolid, y); if (DistanceToHullAcceptable(pca, polygon, entrance.Value, true)) { return(entrance); } entrance = null; break; } } else { if (foundSolid) { foundTransparent = true; } } } } } } } } return(null); }
private static List <Vertices> DetectVertices(ref PolygonCreationAssistance pca) { List <Vertices> polygons = new List <Vertices>(); Vertices polygon; Vertices holePolygon; Vector2?holeEntrance = null; Vector2?polygonEntrance = null; List <Vector2> blackList = new List <Vector2>(); // Check the array you just got. Debug.Assert(pca.IsValid(), "Sizes don't match: Color array must contain texture width * texture height elements."); bool searchOn; do { if (polygons.Count == 0) { polygon = CreateSimplePolygon(pca, Vector2.Zero, Vector2.Zero); if (polygon != null && polygon.Count > 2) { polygonEntrance = GetTopMostVertex(polygon); } } else if (polygonEntrance.HasValue) { polygon = CreateSimplePolygon(pca, polygonEntrance.Value, new Vector2(polygonEntrance.Value.X - 1f, polygonEntrance.Value.Y)); } else { break; } searchOn = false; if (polygon != null && polygon.Count > 2) { if (pca.HoleDetection) { do { holeEntrance = GetHoleHullEntrance(pca, polygon, holeEntrance); if (holeEntrance.HasValue) { if (!blackList.Contains(holeEntrance.Value)) { blackList.Add(holeEntrance.Value); holePolygon = CreateSimplePolygon(pca, holeEntrance.Value, new Vector2(holeEntrance.Value.X + 1, holeEntrance.Value.Y)); if (holePolygon != null && holePolygon.Count > 2) { holePolygon.Add(holePolygon[0]); int vertex2Index; int vertex1Index; if (SplitPolygonEdge(polygon, EdgeAlignment.Vertical, holeEntrance.Value, out vertex1Index, out vertex2Index)) { polygon.InsertRange(vertex2Index, holePolygon); } } } else { break; } } else { break; } } while (true); } polygons.Add(polygon); if (pca.MultipartDetection) { // 1: 95 / 151 // 2: 232 / 252 // while (GetNextHullEntrance(pca, polygonEntrance.Value, out polygonEntrance)) { bool inPolygon = false; for (int i = 0; i < polygons.Count; i++) { polygon = polygons[i]; if (InPolygon(pca, polygon, polygonEntrance.Value)) { inPolygon = true; break; } } if (!inPolygon) { searchOn = true; break; } } } } } while (searchOn); return(polygons); }
/// <summary> /// Detects the vertices of the supplied texture data. /// </summary> /// <param name="data">The texture data.</param> /// <param name="width">The texture width.</param> /// <param name="height">The texture height.</param> /// <param name="holeDetection">if set to <c>true</c> it will perform hole detection.</param> /// <returns></returns> public static Vertices DetectVertices(uint[] data, int width, int height, bool holeDetection) { PolygonCreationAssistance pca = new PolygonCreationAssistance(data, width, height); pca.HoleDetection = holeDetection; List<Vertices> verts = DetectVertices(ref pca); return verts[0]; }