using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace ZIM.Unity { public class UnityQuadrilateral { Vector2 a, b, c, d; // 左下,右下,左上,右上 public UnityQuadrilateral(Vector2 a, Vector2 b, Vector2 c, Vector2 d) { this.a = a; this.b = b; this.c = c; this.d = d; } public Vector2 this[int index] { get { switch (index) { case 0: return this.a; case 1: return this.b; case 2: return this.c; case 3: return this.d; default: return default; } } } public bool IsInScreen(Vector2 size) { if (a.x < b.x && a.y < c.y && b.y < d.y && c.x < d.x && a.x > 0 && a.y > 0 && b.x < size.x && b.y > 0 && c.x > 0 && c.y < size.y && d.x < size.x && d.y < size.y) return true; return false; } public override string ToString() { return $"{a}, {b}, {c}, {d}"; } public Vector2 InterpolationFactors(Vector2 p) { float u, v; float _a = (c.x - d.x + b.x - a.x) * (a.y - c.y) - (c.y - d.y + b.y - a.y) * (a.x - c.x); float _b = (d.x - c.x) * (a.y - c.y) - (d.y - c.y) * (a.x - c.x) + (p.x - c.x) * (c.y - d.y + b.y - a.y) - (p.y - c.y) * (c.x - d.x + b.x - a.x); float _c = (p.x - c.x) * (d.y - c.y) - (p.y - c.y) * (d.x - c.x); if (_a < float.Epsilon) { v = -_c / _b; } else { float delta = _b * _b - 4 * _a * _c; if (delta < 0) { return default; throw new Exception("Delta is smaller than zero."); } float sqrtDelta = Mathf.Sqrt(delta); v = (-_b + sqrtDelta) / (2 * _a); if (v < 0 || v > 1) v = (-_b - sqrtDelta) / (2 * _a); } u = ((p.x - c.x) - (a.x - c.x) * v) / ((d.x - c.x) + (c.x - d.x + b.x - a.x) * v); return new Vector2(u, 1 - v); } public static UnityQuadrilateral Fit(IEnumerable pixels, Vector2 textureSize) { Vector2[] vertex = new Vector2[4] { new Vector2(0, 0), new Vector2(textureSize.x, 0), new Vector2(textureSize.y, 0), textureSize }; Vector2[] dir = new Vector2[4] { new Vector2(1, 1).normalized, new Vector2(-1, 1).normalized, new Vector2(1, -1).normalized, new Vector2(-1, -1).normalized }; (float, Vector2)[] min = new (float, Vector2)[4] { (float.MaxValue, default), (float.MaxValue, default), (float.MaxValue, default), (float.MaxValue, default) }; foreach (var i in pixels) { for (int j = 0; j < 4; j++) { var len = Vector2.Dot(i - vertex[j], dir[j]); if (len < min[j].Item1) min[j] = (len, i); } } return new UnityQuadrilateral(min[0].Item2, min[1].Item2, min[2].Item2, min[3].Item2); //float minX = 0, minY = 0; //float maxX = textureSize.x, maxY = textureSize.y; //foreach (Vector2 p in pixels) //{ // minX = Math.Min(minX, p.x); // minY = Math.Min(minY, p.y); // maxX = Math.Max(maxX, p.x); // maxY = Math.Max(maxY, p.y); //} //Vector2[] vertices = new Vector2[4]; //vertices[0] = new Vector2(minX, minY); // 左下角 //vertices[1] = new Vector2(maxX, minY); // 右下角 //vertices[2] = new Vector2(minX, maxY); // 左上角 //vertices[3] = new Vector2(maxX, maxY); // 右上角 //for (int i = 0; i < 4; i++) //{ // float minDistance = float.MaxValue; // Vector2 closestPoint = default; // foreach (var j in pixels) // { // float distance = (vertices[i] - j).magnitude; // if (distance < minDistance) // { // minDistance = distance; // closestPoint = j; // } // } // vertices[i] = closestPoint; //} //return new Quadrilateral(vertices[0], vertices[1], vertices[2], vertices[3]); } } }