UnityQuadrilateral.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. namespace ZIM.Unity
  6. {
  7. public class UnityQuadrilateral
  8. {
  9. Vector2 a, b, c, d; // 左下,右下,左上,右上
  10. public UnityQuadrilateral(Vector2 a, Vector2 b, Vector2 c, Vector2 d)
  11. {
  12. this.a = a;
  13. this.b = b;
  14. this.c = c;
  15. this.d = d;
  16. }
  17. public Vector2 this[int index]
  18. {
  19. get
  20. {
  21. switch (index)
  22. {
  23. case 0: return this.a;
  24. case 1: return this.b;
  25. case 2: return this.c;
  26. case 3: return this.d;
  27. default: return default;
  28. }
  29. }
  30. }
  31. public bool IsInScreen(Vector2 size)
  32. {
  33. if (a.x < b.x && a.y < c.y && b.y < d.y && c.x < d.x && a.x > 0 && a.y > 0 &&
  34. b.x < size.x && b.y > 0 && c.x > 0 && c.y < size.y && d.x < size.x && d.y < size.y)
  35. return true;
  36. return false;
  37. }
  38. public override string ToString()
  39. {
  40. return $"{a}, {b}, {c}, {d}";
  41. }
  42. public Vector2 InterpolationFactors(Vector2 p)
  43. {
  44. float u, v;
  45. 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);
  46. 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);
  47. float _c = (p.x - c.x) * (d.y - c.y) - (p.y - c.y) * (d.x - c.x);
  48. if (_a < float.Epsilon)
  49. {
  50. v = -_c / _b;
  51. }
  52. else
  53. {
  54. float delta = _b * _b - 4 * _a * _c;
  55. if (delta < 0)
  56. {
  57. return default;
  58. throw new Exception("Delta is smaller than zero.");
  59. }
  60. float sqrtDelta = Mathf.Sqrt(delta);
  61. v = (-_b + sqrtDelta) / (2 * _a);
  62. if (v < 0 || v > 1)
  63. v = (-_b - sqrtDelta) / (2 * _a);
  64. }
  65. u = ((p.x - c.x) - (a.x - c.x) * v) / ((d.x - c.x) + (c.x - d.x + b.x - a.x) * v);
  66. return new Vector2(u, 1 - v);
  67. }
  68. public static UnityQuadrilateral Fit(IEnumerable<Vector2> pixels, Vector2 textureSize)
  69. {
  70. Vector2[] vertex = new Vector2[4] { new Vector2(0, 0), new Vector2(textureSize.x, 0), new Vector2(textureSize.y, 0), textureSize };
  71. 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 };
  72. (float, Vector2)[] min = new (float, Vector2)[4] { (float.MaxValue, default), (float.MaxValue, default), (float.MaxValue, default), (float.MaxValue, default) };
  73. foreach (var i in pixels)
  74. {
  75. for (int j = 0; j < 4; j++)
  76. {
  77. var len = Vector2.Dot(i - vertex[j], dir[j]);
  78. if (len < min[j].Item1)
  79. min[j] = (len, i);
  80. }
  81. }
  82. return new UnityQuadrilateral(min[0].Item2, min[1].Item2, min[2].Item2, min[3].Item2);
  83. //float minX = 0, minY = 0;
  84. //float maxX = textureSize.x, maxY = textureSize.y;
  85. //foreach (Vector2 p in pixels)
  86. //{
  87. // minX = Math.Min(minX, p.x);
  88. // minY = Math.Min(minY, p.y);
  89. // maxX = Math.Max(maxX, p.x);
  90. // maxY = Math.Max(maxY, p.y);
  91. //}
  92. //Vector2[] vertices = new Vector2[4];
  93. //vertices[0] = new Vector2(minX, minY); // 左下角
  94. //vertices[1] = new Vector2(maxX, minY); // 右下角
  95. //vertices[2] = new Vector2(minX, maxY); // 左上角
  96. //vertices[3] = new Vector2(maxX, maxY); // 右上角
  97. //for (int i = 0; i < 4; i++)
  98. //{
  99. // float minDistance = float.MaxValue;
  100. // Vector2 closestPoint = default;
  101. // foreach (var j in pixels)
  102. // {
  103. // float distance = (vertices[i] - j).magnitude;
  104. // if (distance < minDistance)
  105. // {
  106. // minDistance = distance;
  107. // closestPoint = j;
  108. // }
  109. // }
  110. // vertices[i] = closestPoint;
  111. //}
  112. //return new Quadrilateral(vertices[0], vertices[1], vertices[2], vertices[3]);
  113. }
  114. }
  115. }