MB3_UVTransform.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. using UnityEngine;
  2. using System.Collections;
  3. using System;
  4. // A UV Transform is a transform considering only scale and offset it is used to represent the scaling and offset
  5. // from UVs outside the 0,0..1,1 box and material tiling
  6. // Rect objects are used to store the transform
  7. namespace DigitalOpus.MB.Core
  8. {
  9. public struct DVector2
  10. {
  11. static double epsilon = 10e-6;
  12. public double x;
  13. public double y;
  14. public static DVector2 Subtract(DVector2 a, DVector2 b)
  15. {
  16. return new DVector2(a.x - b.x, a.y - b.y);
  17. }
  18. public DVector2(double xx, double yy)
  19. {
  20. x = xx;
  21. y = yy;
  22. }
  23. public DVector2(DVector2 r)
  24. {
  25. x = r.x;
  26. y = r.y;
  27. }
  28. public Vector2 GetVector2()
  29. {
  30. return new Vector2((float)x, (float)y);
  31. }
  32. public bool IsContainedIn(DRect r)
  33. {
  34. if (x >= r.x && y >= r.y && x <= r.x + r.width && y <= r.y + r.height)
  35. {
  36. return true;
  37. } else
  38. {
  39. return false;
  40. }
  41. }
  42. public bool IsContainedInWithMargin(DRect r)
  43. {
  44. if (x >= r.x - epsilon && y >= r.y - epsilon && x <= r.x + r.width + epsilon && y <= r.y + r.height + epsilon)
  45. {
  46. return true;
  47. }
  48. else
  49. {
  50. return false;
  51. }
  52. }
  53. public override string ToString()
  54. {
  55. return string.Format("({0},{1})", x, y);
  56. }
  57. public string ToString(string formatS)
  58. {
  59. return string.Format("({0},{1})", x.ToString(formatS), y.ToString(formatS));
  60. }
  61. public static double Distance(DVector2 a, DVector2 b)
  62. {
  63. double dx = b.x - a.x;
  64. double dy = b.y - a.y;
  65. return System.Math.Sqrt(dx * dx + dy * dy);
  66. }
  67. }
  68. public struct DRect
  69. {
  70. public double x;
  71. public double y;
  72. public double width;
  73. public double height;
  74. public DRect(Rect r)
  75. {
  76. x = r.x;
  77. y = r.y;
  78. width = r.width;
  79. height = r.height;
  80. }
  81. public DRect(Vector2 o, Vector2 s)
  82. {
  83. x = o.x;
  84. y = o.y;
  85. width = s.x;
  86. height = s.y;
  87. }
  88. public DRect(DRect r)
  89. {
  90. x = r.x;
  91. y = r.y;
  92. width = r.width;
  93. height = r.height;
  94. }
  95. public DRect(float xx, float yy, float w, float h)
  96. {
  97. x = xx;
  98. y = yy;
  99. width = w;
  100. height = h;
  101. }
  102. public DRect(double xx, double yy, double w, double h)
  103. {
  104. x = xx;
  105. y = yy;
  106. width = w;
  107. height = h;
  108. }
  109. public Rect GetRect()
  110. {
  111. return new Rect((float)x, (float)y, (float)width, (float)height);
  112. }
  113. public DVector2 minD
  114. {
  115. get
  116. {
  117. return new DVector2(x, y);
  118. }
  119. }
  120. public DVector2 maxD
  121. {
  122. get
  123. {
  124. return new DVector2((x + width), (y + height));
  125. }
  126. }
  127. public Vector2 min
  128. {
  129. get
  130. {
  131. return new Vector2((float)x, (float)y);
  132. }
  133. }
  134. public Vector2 max
  135. {
  136. get
  137. {
  138. return new Vector2((float)(x + width), (float)(y + height));
  139. }
  140. }
  141. public Vector2 size {
  142. get {
  143. return new Vector2((float)(width), (float)(height));
  144. }
  145. }
  146. public DVector2 center
  147. {
  148. get
  149. {
  150. return new DVector2(x + width / 2.0, y + height / 2.0);
  151. }
  152. }
  153. public override bool Equals(object obj)
  154. {
  155. DRect dr = (DRect) obj;
  156. if (dr.x == x && dr.y == y && dr.width == width && dr.height == height)
  157. {
  158. return true;
  159. }
  160. return false;
  161. }
  162. public static bool operator ==(DRect a, DRect b)
  163. {
  164. return a.Equals(b);
  165. }
  166. public static bool operator !=(DRect a, DRect b)
  167. {
  168. return !a.Equals(b);
  169. }
  170. public override string ToString()
  171. {
  172. return String.Format("(x={0},y={1},w={2},h={3})", x.ToString("F5"), y.ToString("F5"), width.ToString("F5"), height.ToString("F5"));
  173. }
  174. public void Expand(float amt)
  175. {
  176. x -= amt;
  177. y -= amt;
  178. width += amt * 2;
  179. height += amt * 2;
  180. }
  181. public bool Encloses(DRect smallToTestIfFits)
  182. {
  183. double smnx = smallToTestIfFits.x;
  184. double smny = smallToTestIfFits.y;
  185. double smxx = smallToTestIfFits.x + smallToTestIfFits.width;
  186. double smxy = smallToTestIfFits.y + smallToTestIfFits.height;
  187. //expand slightly to deal with rounding errors
  188. double bmnx = this.x;
  189. double bmny = this.y;
  190. double bmxx = this.x + this.width;
  191. double bmxy = this.y + this.height;
  192. return bmnx <= smnx && smnx <= bmxx &&
  193. bmnx <= smxx && smxx <= bmxx &&
  194. bmny <= smny && smny <= bmxy &&
  195. bmny <= smxy && smxy <= bmxy;
  196. }
  197. public override int GetHashCode ()
  198. {
  199. return x.GetHashCode() ^ y.GetHashCode() ^ width.GetHashCode() ^ height.GetHashCode();
  200. }
  201. }
  202. public class MB3_UVTransformUtility
  203. {
  204. public static void Test()
  205. {
  206. /*
  207. Debug.Log("Running test");
  208. DRect rawUV = new DRect(.25, .25, 1.5, 1.5);
  209. DRect rawMat = new DRect(.5, .5, 2, 2);
  210. DRect rawCombined = CombineTransforms(ref rawUV, ref rawMat);
  211. DRect matInvHierarchy = new DRect(rawMat.GetRect());
  212. InvertHierarchy(ref rawUV, ref matInvHierarchy);
  213. DRect invertHierarchyCombined = CombineTransforms(ref matInvHierarchy, ref rawUV);
  214. //These transforms should be the same
  215. Debug.Log("These should be same " + rawCombined + " " + invertHierarchyCombined);
  216. //New transform that should fit in combined
  217. DRect otherUV = new DRect(1,1,1.5,1.5);
  218. DRect otherMat = new DRect(0, 0, 1, 1);
  219. DRect otherCombined = CombineTransforms(ref otherUV, ref otherMat);
  220. Debug.Log("Other : " + otherCombined);
  221. Debug.Log("Other fits = " + RectContains(ref rawCombined, ref otherCombined));
  222. DRect invOtherCombined = InverseTransform(ref otherCombined);
  223. Debug.Log(TransformPoint(ref otherCombined, new Vector2(0, 0)) + " " + TransformPoint(ref otherCombined, new Vector2(1, 1)));
  224. Debug.Log(TransformPoint(ref invOtherCombined, new Vector2(0,0)) + " " + TransformPoint(ref invOtherCombined, new Vector2(1,1)).ToString("f5")
  225. + " " + TransformPoint(ref invOtherCombined, new Vector2(2, 2)).ToString("f5")
  226. + " " + TransformPoint(ref invOtherCombined, new Vector2(3, 3)).ToString("f5"));
  227. DRect src2combined = CombineTransforms(ref invOtherCombined, ref rawCombined);
  228. Debug.Log(TransformPoint(ref src2combined, new Vector2(0, 0)) + " " + TransformPoint(ref src2combined, new Vector2(1, 1)).ToString("f5")
  229. + " " + TransformPoint(ref src2combined, new Vector2(2, 2)).ToString("f5")
  230. + " " + TransformPoint(ref src2combined, new Vector2(3, 3)).ToString("f5"));
  231. */
  232. //DRect rawUV = new DRect(0, 0, 1, 1);
  233. DRect rawMat = new DRect(.5, .5, 2, 2);
  234. DRect fullSample = new DRect(.25,.25,3,3);
  235. //DRect altasRect = new DRect(0, 0, 1, 1);
  236. DRect invRawMat = InverseTransform(ref rawMat);
  237. DRect invFullSample = InverseTransform(ref fullSample);
  238. DRect relativeTransform = CombineTransforms(ref rawMat, ref invFullSample);
  239. Debug.Log(invRawMat);
  240. Debug.Log(relativeTransform);
  241. Debug.Log("one mat trans " + TransformPoint(ref rawMat, new Vector2(1, 1)));
  242. Debug.Log("one inv mat trans " + TransformPoint(ref invRawMat, new Vector2(1, 1)).ToString("f4"));
  243. Debug.Log("zero " + TransformPoint(ref relativeTransform, new Vector2(0, 0)).ToString("f4"));
  244. Debug.Log("one " + TransformPoint(ref relativeTransform, new Vector2(1, 1)).ToString("f4"));
  245. }
  246. public static float TransformX(DRect r, double x)
  247. {
  248. return (float) (r.width * x + r.x);
  249. }
  250. public static DRect CombineTransforms(ref DRect r1, ref DRect r2)
  251. {
  252. DRect rCombined = new DRect(r1.x * r2.width + r2.x,
  253. r1.y * r2.height + r2.y,
  254. r1.width * r2.width,
  255. r1.height * r2.height);
  256. //rCombined.x = rCombined.x - Mathf.FloorToInt(rCombined.x);
  257. //rCombined.y = rCombined.y - Mathf.FloorToInt(rCombined.y);
  258. return rCombined;
  259. }
  260. public static Rect CombineTransforms(ref Rect r1, ref Rect r2)
  261. {
  262. Rect rCombined = new Rect(r1.x * r2.width + r2.x,
  263. r1.y * r2.height + r2.y,
  264. r1.width * r2.width,
  265. r1.height * r2.height);
  266. //rCombined.x = rCombined.x - Mathf.FloorToInt(rCombined.x);
  267. //rCombined.y = rCombined.y - Mathf.FloorToInt(rCombined.y);
  268. return rCombined;
  269. }
  270. //since the 0,0..1,1 box is tiled the offset should always be between 0 and 1
  271. /*
  272. public static void Canonicalize(ref DRect r, double minX, double minY)
  273. {
  274. r.x = r.x - Mathf.FloorToInt((float) r.x);
  275. if (r.x < minX) { r.x += Mathf.CeilToInt((float)minX); }
  276. r.y = r.y - Mathf.FloorToInt((float) r.y);
  277. if (r.y < minY) { r.y += Mathf.CeilToInt((float)minY); }
  278. }
  279. public static void Canonicalize(ref Rect r, float minX, float minY)
  280. {
  281. r.x = r.x - Mathf.FloorToInt(r.x);
  282. if (r.x < minX) { r.x += Mathf.CeilToInt(minX); }
  283. r.y = r.y - Mathf.FloorToInt(r.y);
  284. if (r.y < minY) { r.y += Mathf.CeilToInt(minY); }
  285. }
  286. */
  287. public static DRect InverseTransform(ref DRect t)
  288. {
  289. DRect tinv = new DRect();
  290. tinv.x = -t.x / t.width;
  291. tinv.y = -t.y / t.height;
  292. tinv.width = 1f / t.width;
  293. tinv.height = 1f / t.height;
  294. return tinv;
  295. }
  296. public static DRect GetShiftTransformToFitBinA(ref DRect A, ref DRect B)
  297. {
  298. DVector2 ac = A.center;
  299. DVector2 bc = B.center;
  300. DVector2 diff = DVector2.Subtract(ac, bc);
  301. double dx = Convert.ToInt32(diff.x);
  302. double dy = Convert.ToInt32(diff.y);
  303. return new DRect(dx,dy,1.0,1.0);
  304. }
  305. /// <summary>
  306. /// shifts willBeIn so it is centered in uvRect1, then find a rect that encloses both
  307. /// </summary>
  308. /// <param name="uvRect1"></param>
  309. /// <param name="willBeIn"></param>
  310. /// <returns></returns>
  311. public static DRect GetEncapsulatingRectShifted(ref DRect uvRect1, ref DRect willBeIn)
  312. {
  313. DVector2 bc = uvRect1.center;
  314. DVector2 tfc = willBeIn.center;
  315. DVector2 diff = DVector2.Subtract(bc, tfc);
  316. double dx = Convert.ToInt32(diff.x);
  317. double dy = Convert.ToInt32(diff.y);
  318. DRect uvRect2 = new DRect(willBeIn);
  319. uvRect2.x += dx;
  320. uvRect2.y += dy;
  321. double smnx = uvRect1.x;
  322. double smny = uvRect1.y;
  323. double smxx = uvRect1.x + uvRect1.width;
  324. double smxy = uvRect1.y + uvRect1.height;
  325. double bmnx = uvRect2.x;
  326. double bmny = uvRect2.y;
  327. double bmxx = uvRect2.x + uvRect2.width;
  328. double bmxy = uvRect2.y + uvRect2.height;
  329. double minx, miny, maxx, maxy;
  330. minx = maxx = smnx;
  331. miny = maxy = smny;
  332. if (bmnx < minx) minx = bmnx;
  333. if (smnx < minx) minx = smnx;
  334. if (bmny < miny) miny = bmny;
  335. if (smny < miny) miny = smny;
  336. if (bmxx > maxx) maxx = bmxx;
  337. if (smxx > maxx) maxx = smxx;
  338. if (bmxy > maxy) maxy = bmxy;
  339. if (smxy > maxy) maxy = smxy;
  340. DRect uvRectCombined = new DRect(minx, miny, maxx - minx, maxy - miny);
  341. return uvRectCombined;
  342. }
  343. public static DRect GetEncapsulatingRect(ref DRect uvRect1, ref DRect uvRect2)
  344. {
  345. double smnx = uvRect1.x;
  346. double smny = uvRect1.y;
  347. double smxx = uvRect1.x + uvRect1.width;
  348. double smxy = uvRect1.y + uvRect1.height;
  349. double bmnx = uvRect2.x;
  350. double bmny = uvRect2.y;
  351. double bmxx = uvRect2.x + uvRect2.width;
  352. double bmxy = uvRect2.y + uvRect2.height;
  353. double minx, miny, maxx, maxy;
  354. minx = maxx = smnx;
  355. miny = maxy = smny;
  356. if (bmnx < minx) minx = bmnx;
  357. if (smnx < minx) minx = smnx;
  358. if (bmny < miny) miny = bmny;
  359. if (smny < miny) miny = smny;
  360. if (bmxx > maxx) maxx = bmxx;
  361. if (smxx > maxx) maxx = smxx;
  362. if (bmxy > maxy) maxy = bmxy;
  363. if (smxy > maxy) maxy = smxy;
  364. DRect uvRectCombined = new DRect(minx, miny, maxx - minx, maxy - miny);
  365. return uvRectCombined;
  366. }
  367. /*
  368. public static void InvertHierarchy(ref DRect uvRect, ref DRect matRect)
  369. {
  370. matRect.x = (uvRect.x * matRect.width + matRect.x - uvRect.x) / uvRect.width;
  371. matRect.y = (uvRect.y * matRect.height + matRect.y - uvRect.y) / uvRect.height;
  372. }
  373. */
  374. public static bool RectContainsShifted(ref DRect bucket, ref DRect tryFit)
  375. {
  376. //get the centers of bucket and tryFit
  377. DVector2 bc = bucket.center;
  378. DVector2 tfc = tryFit.center;
  379. DVector2 diff = DVector2.Subtract(bc, tfc);
  380. double dx = Convert.ToInt32(diff.x);
  381. double dy = Convert.ToInt32(diff.y);
  382. DRect tmp = new DRect(tryFit);
  383. tmp.x += dx;
  384. tmp.y += dy;
  385. return bucket.Encloses(tmp);
  386. }
  387. public static bool RectContainsShifted(ref Rect bucket, ref Rect tryFit)
  388. {
  389. //get the centers of bucket and tryFit
  390. Vector2 bc = bucket.center;
  391. Vector2 tfc = tryFit.center;
  392. Vector2 diff = bc - tfc;
  393. float dx = Convert.ToInt32(diff.x);
  394. float dy = Convert.ToInt32(diff.y);
  395. Rect tmp = new Rect(tryFit);
  396. tmp.x += dx;
  397. tmp.y += dy;
  398. return RectContains(ref bucket, ref tmp);
  399. }
  400. public static bool LineSegmentContainsShifted(float bucketOffset, float bucketLength, float tryFitOffset, float tryFitLength)
  401. {
  402. Debug.Assert(bucketLength >= 0);
  403. Debug.Assert(tryFitLength >= 0);
  404. float bc = bucketOffset + bucketLength / 2f;
  405. float tfc = tryFitOffset + tryFitLength / 2f;
  406. float diff = bc - tfc;
  407. float delta = Convert.ToInt32(diff);
  408. tryFitOffset += delta;
  409. float sminx = tryFitOffset;
  410. float smaxx = tryFitOffset + tryFitLength;
  411. float bminx = bucketOffset - 10e-3f;
  412. float bmaxx = bucketOffset + bucketLength + 10e-3f;
  413. return bminx <= sminx && sminx <= bmaxx &&
  414. bminx <= smaxx && smaxx <= bmaxx;
  415. }
  416. public static bool RectContains(ref DRect bigRect, ref DRect smallToTestIfFits)
  417. {
  418. double sminx = smallToTestIfFits.x;
  419. double sminy = smallToTestIfFits.y;
  420. double smaxx = smallToTestIfFits.x + smallToTestIfFits.width;
  421. double smaxy = smallToTestIfFits.y + smallToTestIfFits.height;
  422. //expand slightly to deal with rounding errors
  423. double bminx = bigRect.x - 10e-3f;
  424. double bminy = bigRect.y - 10e-3f;
  425. double bmaxx = bigRect.x + bigRect.width + 10e-3f;
  426. double bmaxy = bigRect.y + bigRect.height + 10e-3f;
  427. //is smn in box
  428. /*
  429. string s = "";
  430. s += (bmnx <= smnx);
  431. s += (smnx <= bmxx);
  432. s += (bmnx <= smxx);
  433. s += String.Format("{0} {1} {2}",(smxx <= bmxx).ToString(), smxx.ToString("F5"), bmxx.ToString("F5"));
  434. s += String.Format("{0} {1} {2}",(bmny <= smny), bmny.ToString("F5"), smny.ToString("F5"));
  435. s += (smny <= bmxy);
  436. s += (bmny <= smxy);
  437. s += String.Format("{0} {1} {2}",(smxy <= bmxy).ToString(), smxy.ToString("F5"), bmxy.ToString("F5"));
  438. Debug.Log("==== " + bigRect + " " + smallToTestIfFits + " " + s);
  439. */
  440. return bminx <= sminx && sminx <= bmaxx &&
  441. bminx <= smaxx && smaxx <= bmaxx &&
  442. bminy <= sminy && sminy <= bmaxy &&
  443. bminy <= smaxy && smaxy <= bmaxy;
  444. }
  445. public static bool RectContains(ref Rect bigRect, ref Rect smallToTestIfFits)
  446. {
  447. float smnx = smallToTestIfFits.x;
  448. float smny = smallToTestIfFits.y;
  449. float smxx = smallToTestIfFits.x + smallToTestIfFits.width;
  450. float smxy = smallToTestIfFits.y + smallToTestIfFits.height;
  451. //expand slightly to deal with rounding errors
  452. float bmnx = bigRect.x - 10e-3f;
  453. float bmny = bigRect.y - 10e-3f;
  454. float bmxx = bigRect.x + bigRect.width + 10e-3f;
  455. float bmxy = bigRect.y + bigRect.height + 10e-3f;
  456. //is smn in box
  457. /*
  458. Debug.Log("==== " + bigRect + " " + smallToTestIfFits);
  459. Debug.Log(bmnx <= smnx);
  460. Debug.Log(smnx <= bmxx);
  461. Debug.Log(bmnx <= smxx);
  462. Debug.LogFormat("{0} {1} {2}", (smxx <= bmxx).ToString(), smxx.ToString("F5"), bmxx.ToString("F5"));
  463. Debug.LogFormat("{0} {1} {2}", (bmny <= smny), bmny.ToString("F5"), smny.ToString("F5"));
  464. Debug.Log(smny <= bmxy);
  465. Debug.Log(bmny <= smxy);
  466. Debug.LogFormat("{0} {1} {2}", (smxy <= bmxy).ToString(), smxy.ToString("F5"), bmxy.ToString("F5"));
  467. Debug.Log("----------------");
  468. */
  469. return bmnx <= smnx && smnx <= bmxx &&
  470. bmnx <= smxx && smxx <= bmxx &&
  471. bmny <= smny && smny <= bmxy &&
  472. bmny <= smxy && smxy <= bmxy;
  473. }
  474. public static Vector2 TransformPoint(ref DRect r, Vector2 p)
  475. {
  476. return new Vector2((float) (r.width * p.x + r.x),(float)(r.height * p.y + r.y));
  477. }
  478. public static DVector2 TransformPoint(ref DRect r, DVector2 p)
  479. {
  480. return new DVector2((r.width * p.x + r.x), (r.height * p.y + r.y));
  481. }
  482. }
  483. }