public Polygon RectangleInside() { var p1 = Vector2.zero; var p2 = Vector2.zero; var maxLength = float.MinValue; ForEachEdge((a, b, i) => { var len = (a - b).magnitude; if (len > maxLength) { p1 = a; p2 = b; maxLength = len; } }); var rotated = Rotate(GeometryHelpers.Angle(p1 - p2)); var minY = rotated.Vertices.Min(v => v.y); var greatestDistance = rotated.Vertices.Max(v => v.y - minY); var normal = GeometryHelpers.Rotate90(p2 - p1).normalized; var newHouse = new Polygon(p1, p2, p2 - GeometryHelpers.Scale(normal, greatestDistance), p1 - GeometryHelpers.Scale(normal, greatestDistance)).ZoomShrink(0.2f); newHouse = newHouse.Translate(newHouse.Center - Center); return(newHouse); }
public float AngleAtVertex(int index) { var pt = Vertices[index]; var prev = GetPreviousVertex(index); var next = GetNextVertex(index); return(GeometryHelpers.AngleThreePoints(prev, pt, next)); }
public Polygon Peel(Vector2 v1, float amount) { var v2 = GetNextVertex(v1); var n = GeometryHelpers.Scale(GeometryHelpers.Normalize(GeometryHelpers.Rotate90(v2 - v1)), amount); return(Cut(v1 + n, v2 + n, 0).First()); }
public Vector2 GetCenter() { var sum = new Vector2(); Vertices.ForEach(v => sum += v); sum = GeometryHelpers.Scale(sum, 1f / Vertices.Count); return(sum); }
public static float AngleThreePoints(Vector2 a, Vector2 b, Vector2 c) { var v1 = b - a; var v2 = c - b; var cross = GeometryHelpers.Cross(v1, v2); var dot = Vector2.Dot(v1, v2); return((float)Math.Atan2(cross, dot)); }
public Polygon ZoomShrink(float amount) { var newVertices = Vertices.Select(v => { var d = Center - v; return(v + GeometryHelpers.Scale(d, amount)); }).ToList(); return(new Polygon(newVertices)); }
public Vector2 Center() { var c = new Vector2(); foreach (var v in Vertices) { c = c + v.C; } return(GeometryHelpers.Scale(c, 1f / Vertices.Count)); }
public IEnumerable <Polygon> Bisect(Vector2 vertex, float ratio = 0.5f, float angle = 0.0f, float gap = 0.0f) { var next = GetNextVertex(vertex); var p1 = GeometryHelpers.Interpolate(vertex, next, ratio); var d = next - vertex; var cosB = Math.Cos(angle); var sinB = Math.Sin(angle); var vx = d.x * cosB - d.y * sinB; var vy = d.y * cosB + d.x * sinB; var p2 = new Vector2((float)(p1.x - vy), (float)(p1.y + vx)); return(Cut(p1, p2, gap)); }
public Polygon Shrink(IList <float> shrinkAmounts) { var newPoly = new Polygon(this); ForEachEdge((p1, p2, index) => { var amount = shrinkAmounts[index]; if (amount > 0) { var n = GeometryHelpers.Scale(GeometryHelpers.Normalize(GeometryHelpers.Rotate90(p2 - p1)), amount); newPoly = newPoly.Cut(p1 + n, p2 + n, 0).First(); } }); return(newPoly); }
public Polygon SmoothVertices(float amount = 1f) { var len = Vertices.Count; var v1 = Vertices[len - 1]; var v2 = Vertices[0]; var newVertices = new List <Vector2> (); for (var v = 0; v < Vertices.Count; v++) { var v0 = v1; v1 = v2; v2 = Vertices[(v + 1) % len]; newVertices.Add(GeometryHelpers.SmoothVertex(v1, v0, v2)); } return(new Polygon(newVertices)); }
public static float Cross(Vector2 a, Vector2 b) { return(GeometryHelpers.CrossProduct(a.x, a.y, b.x, b.y)); }
public Polygon SortPointsClockwise() { var sortedVertices = Vertices.OrderBy(v => GeometryHelpers.Angle(v - Center)).ToList(); return(new Polygon(sortedVertices)); }
public Polygon Rotate(float angle) { return(new Polygon(Vertices.Select(vertex => GeometryHelpers.RotateAoundPoint(vertex, Center, angle)))); }
public IEnumerable <Polygon> Cut(Vector2 p1, Vector2 p2, float gap) { var x1 = p1.x; var y1 = p1.y; var dx1 = p2.x - x1; var dy1 = p2.y - y1; var len = Vertices.Count; var edge1 = 0; var ratio1 = 0.0f; var edge2 = 0; var ratio2 = 0.0f; var count = 0; for (var i = 0; i < len; i++) { var v0 = Vertices[i]; var v1 = Vertices[(i + 1) % len]; var x2 = v0.x; var y2 = v0.y; var dx2 = v1.x - x2; var dy2 = v1.y - y2; var t = GeometryHelpers.IntersectLines(x1, y1, dx1, dy1, x2, y2, dx2, dy2); if (t.y >= 0 && t.y <= 1) { switch (count) { case 0: edge1 = i; ratio1 = t.x; break; case 1: edge2 = i; ratio2 = t.x; break; } count++; } } if (count == 2) { var point1 = p1 + GeometryHelpers.Scale(p2 - p1, ratio1); var point2 = p1 + GeometryHelpers.Scale(p2 - p1, ratio2); var half1 = new Polygon(Vertices.GetRange(edge1 + 1, edge2 - edge1)); half1.Vertices.Insert(0, point1); half1.Vertices.Add(point2); var half2 = new Polygon(Vertices.GetRange(edge2 + 1, Vertices.Count - edge2 - 1).Concat(Vertices.GetRange(0, edge1 + 1))); half2.Vertices.Insert(0, point2); half2.Vertices.Add(point1); if (gap > 0) { half1 = half1.Peel(point2, gap / 2); half2 = half2.Peel(point1, gap / 2); } var v = VectorI(edge1); return(GeometryHelpers.CrossProduct(dx1, dy1, v.x, v.y) > 0 ? new [] { half1, half2 } : new [] { half2, half1 }); } return(new [] { new Polygon(this) }); }
public Polygon Buffer(IList <float> shrinkAmounts) { var newPoly = new Polygon(); ForEachEdge((p1, p2, index) => { var amount = shrinkAmounts[index]; if (amount <= 0.01) { newPoly.Vertices.Add(p1); newPoly.Vertices.Add(p2); } else { var n = GeometryHelpers.Scale(GeometryHelpers.Normalize(GeometryHelpers.Rotate90(p2 - p1)), amount); newPoly.Vertices.Add(p1 + n); newPoly.Vertices.Add(p2 + n); } }); bool wasCut; var lastEdge = 0; do { wasCut = false; var n = newPoly.Vertices.Count; for (var i = lastEdge; i < n - 2; i++) { lastEdge = i; var p11 = newPoly.Vertices[i]; var p12 = newPoly.Vertices[i + 1]; var x1 = p11.x; var y1 = p11.y; var dx1 = p12.x - x1; var dy1 = p12.y - y1; var maxJ = i > 0 ? n : n - 1; for (var j = i + 2; j < maxJ; j++) { var p21 = newPoly.Vertices[j]; var p22 = j < n - 1 ? newPoly.Vertices[j + 1] : newPoly.Vertices[0]; var x2 = p21.x; var y2 = p21.y; var dx2 = p22.x - x2; var dy2 = p22.y - y2; var intersect = GeometryHelpers.IntersectLines(x1, y1, dx1, dy1, x2, y2, dx2, dy2); if (intersect.x > Delta && intersect.x < (1 - Delta) && intersect.y > Delta && intersect.y < (1 - Delta)) { var pn = new Vector2(x1 + dx1 * intersect.x, y1 + dy1 * intersect.x); newPoly.Vertices.Insert(j + 1, pn); newPoly.Vertices.Insert(i + 1, pn); wasCut = true; break; } } } } while (wasCut); var regular = Enumerable.Range(0, newPoly.Vertices.Count).ToList(); Polygon bestPart = null; var bestPartSq = float.MinValue; while (regular.Count > 0) { var indices = new List <int> (); var start = regular[0]; var i = start; do { indices.Add(i); regular.Remove(i); var next = (i + 1) % newPoly.Vertices.Count; var v = newPoly.Vertices[next]; var next1 = newPoly.Vertices.IndexOf(v); if (next1 == next) { next1 = newPoly.Vertices.LastIndexOf(v); } i = next1 == -1 ? next : next1; } while (i != start && indices.Count < 1000); if (indices.Count >= 999) { indices = indices.Take(4).ToList(); } var poly = new Polygon(indices.Select(v => newPoly.Vertices[v])); var s = poly.Area(); if (s > bestPartSq) { bestPart = poly; bestPartSq = s; } } return(bestPart); }