using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace Assets.Common { public static class PointUtils { public static Point Mean(IEnumerable points) { var result = new Point(0, 0); var i = 0; foreach (var point in points) { result.x = (result.x * i + point.x) / (i + 1); result.y = (result.y * i + point.y) / (i + 1); i++; } return result; } public static IEnumerable CalculateNormals(IEnumerable points) { var pairs = points.RotateRight().Zip(points, (a, b) => (a, b)); var thirds = pairs.Zip(points.RotateLeft(), (pair, c) => (pair.a, pair.b, c)); return thirds.Select(third => { var left = (third.a - third.b).Direction; var right = (third.c - third.b).Direction; return ((left + right) / 2).Direction * (IsClockwise(third.a, third.b, third.c) ? -1 : 1); }); } public static double AngleBetween(Point center, Point a, Point b) { a = a - center; b = b - center; var dot = a.x * b.x + a.y * b.y; var det = a.x * b.y - a.y * b.x; var angle = Math.Atan2(det, dot); return angle > 0 ? angle : 2*Math.PI + angle; } public static bool IsClockwise(Point center, Point a, Point b) { var xa = a.x - center.x; var xb = b.x - center.x; var ya = a.y - center.y; var yb = b.y - center.y; return xa * yb - xb * ya < 0; } public static bool IsClockwise(IEnumerable points) { return points.Zip(points.RotateRight(), (a, b) => (b.x - a.x) * (b.y + a.y)).Aggregate((a, b) => a + b) < 0; } public static bool IsPointInside(Point point, IEnumerable points) { var polygon = points.ToArray(); var j = polygon.Length - 1; var inside = false; for (int i = 0; i < polygon.Length; j = i++) { var pi = polygon[i]; var pj = polygon[j]; if (((pi.y <= point.y && point.y < pj.y) || (pj.y <= point.y && point.y < pi.y)) && (point.x < (pj.x - pi.x) * (point.y - pi.y) / (pj.y - pi.y) + pi.x)) inside = !inside; } return inside; } } }