MarchingSquares.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. using System.Collections.Generic;
  2. using FarseerPhysics.Collision;
  3. using Microsoft.Xna.Framework;
  4. namespace FarseerPhysics.Common
  5. {
  6. // Ported by Matthew Bettcher - Feb 2011
  7. /*
  8. Copyright (c) 2010, Luca Deltodesco
  9. All rights reserved.
  10. Redistribution and use in source and binary forms, with or without modification, are permitted
  11. provided that the following conditions are met:
  12. * Redistributions of source code must retain the above copyright notice, this list of conditions
  13. and the following disclaimer.
  14. * Redistributions in binary form must reproduce the above copyright notice, this list of
  15. conditions and the following disclaimer in the documentation and/or other materials provided
  16. with the distribution.
  17. * Neither the name of the nape project nor the names of its contributors may be used to endorse
  18. or promote products derived from this software without specific prior written permission.
  19. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  20. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  21. FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  22. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  25. IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  26. OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. public static class MarchingSquares
  29. {
  30. /// <summary>
  31. /// Marching squares over the given domain using the mesh defined via the dimensions
  32. /// (wid,hei) to build a set of polygons such that f(x,y) less than 0, using the given number
  33. /// 'bin' for recursive linear inteprolation along cell boundaries.
  34. ///
  35. /// if 'comb' is true, then the polygons will also be composited into larger possible concave
  36. /// polygons.
  37. /// </summary>
  38. /// <param name="domain"></param>
  39. /// <param name="cellWidth"></param>
  40. /// <param name="cellHeight"></param>
  41. /// <param name="f"></param>
  42. /// <param name="lerpCount"></param>
  43. /// <param name="combine"></param>
  44. /// <returns></returns>
  45. public static List<Vertices> DetectSquares(AABB domain, float cellWidth, float cellHeight, sbyte[,] f,
  46. int lerpCount, bool combine)
  47. {
  48. CxFastList<GeomPoly> ret = new CxFastList<GeomPoly>();
  49. List<Vertices> verticesList = new List<Vertices>();
  50. //NOTE: removed assignments as they were not used.
  51. List<GeomPoly> polyList;
  52. GeomPoly gp;
  53. int xn = (int)(domain.Extents.X * 2 / cellWidth);
  54. bool xp = xn == (domain.Extents.X * 2 / cellWidth);
  55. int yn = (int)(domain.Extents.Y * 2 / cellHeight);
  56. bool yp = yn == (domain.Extents.Y * 2 / cellHeight);
  57. if (!xp) xn++;
  58. if (!yp) yn++;
  59. sbyte[,] fs = new sbyte[xn + 1, yn + 1];
  60. GeomPolyVal[,] ps = new GeomPolyVal[xn + 1, yn + 1];
  61. //populate shared function lookups.
  62. for (int x = 0; x < xn + 1; x++)
  63. {
  64. int x0;
  65. if (x == xn) x0 = (int)domain.UpperBound.X;
  66. else x0 = (int)(x * cellWidth + domain.LowerBound.X);
  67. for (int y = 0; y < yn + 1; y++)
  68. {
  69. int y0;
  70. if (y == yn) y0 = (int)domain.UpperBound.Y;
  71. else y0 = (int)(y * cellHeight + domain.LowerBound.Y);
  72. fs[x, y] = f[x0, y0];
  73. }
  74. }
  75. //generate sub-polys and combine to scan lines
  76. for (int y = 0; y < yn; y++)
  77. {
  78. float y0 = y * cellHeight + domain.LowerBound.Y;
  79. float y1;
  80. if (y == yn - 1) y1 = domain.UpperBound.Y;
  81. else y1 = y0 + cellHeight;
  82. GeomPoly pre = null;
  83. for (int x = 0; x < xn; x++)
  84. {
  85. float x0 = x * cellWidth + domain.LowerBound.X;
  86. float x1;
  87. if (x == xn - 1) x1 = domain.UpperBound.X;
  88. else x1 = x0 + cellWidth;
  89. gp = new GeomPoly();
  90. int key = MarchSquare(f, fs, ref gp, x, y, x0, y0, x1, y1, lerpCount);
  91. if (gp.Length != 0)
  92. {
  93. if (combine && pre != null && (key & 9) != 0)
  94. {
  95. combLeft(ref pre, ref gp);
  96. gp = pre;
  97. }
  98. else
  99. ret.Add(gp);
  100. ps[x, y] = new GeomPolyVal(gp, key);
  101. }
  102. else
  103. gp = null;
  104. pre = gp;
  105. }
  106. }
  107. if (!combine)
  108. {
  109. polyList = ret.GetListOfElements();
  110. foreach (GeomPoly poly in polyList)
  111. {
  112. verticesList.Add(new Vertices(poly.Points.GetListOfElements()));
  113. }
  114. return verticesList;
  115. }
  116. //combine scan lines together
  117. for (int y = 1; y < yn; y++)
  118. {
  119. int x = 0;
  120. while (x < xn)
  121. {
  122. GeomPolyVal p = ps[x, y];
  123. //skip along scan line if no polygon exists at this point
  124. if (p == null)
  125. {
  126. x++;
  127. continue;
  128. }
  129. //skip along if current polygon cannot be combined above.
  130. if ((p.Key & 12) == 0)
  131. {
  132. x++;
  133. continue;
  134. }
  135. //skip along if no polygon exists above.
  136. GeomPolyVal u = ps[x, y - 1];
  137. if (u == null)
  138. {
  139. x++;
  140. continue;
  141. }
  142. //skip along if polygon above cannot be combined with.
  143. if ((u.Key & 3) == 0)
  144. {
  145. x++;
  146. continue;
  147. }
  148. float ax = x * cellWidth + domain.LowerBound.X;
  149. float ay = y * cellHeight + domain.LowerBound.Y;
  150. CxFastList<Vector2> bp = p.GeomP.Points;
  151. CxFastList<Vector2> ap = u.GeomP.Points;
  152. //skip if it's already been combined with above polygon
  153. if (u.GeomP == p.GeomP)
  154. {
  155. x++;
  156. continue;
  157. }
  158. //combine above (but disallow the hole thingies
  159. CxFastListNode<Vector2> bi = bp.Begin();
  160. while (Square(bi.Elem().Y - ay) > Settings.Epsilon || bi.Elem().X < ax) bi = bi.Next();
  161. //NOTE: Unused
  162. //Vector2 b0 = bi.elem();
  163. Vector2 b1 = bi.Next().Elem();
  164. if (Square(b1.Y - ay) > Settings.Epsilon)
  165. {
  166. x++;
  167. continue;
  168. }
  169. bool brk = true;
  170. CxFastListNode<Vector2> ai = ap.Begin();
  171. while (ai != ap.End())
  172. {
  173. if (VecDsq(ai.Elem(), b1) < Settings.Epsilon)
  174. {
  175. brk = false;
  176. break;
  177. }
  178. ai = ai.Next();
  179. }
  180. if (brk)
  181. {
  182. x++;
  183. continue;
  184. }
  185. CxFastListNode<Vector2> bj = bi.Next().Next();
  186. if (bj == bp.End()) bj = bp.Begin();
  187. while (bj != bi)
  188. {
  189. ai = ap.Insert(ai, bj.Elem()); // .clone()
  190. bj = bj.Next();
  191. if (bj == bp.End()) bj = bp.Begin();
  192. u.GeomP.Length++;
  193. }
  194. //u.p.simplify(float.Epsilon,float.Epsilon);
  195. //
  196. ax = x + 1;
  197. while (ax < xn)
  198. {
  199. GeomPolyVal p2 = ps[(int)ax, y];
  200. if (p2 == null || p2.GeomP != p.GeomP)
  201. {
  202. ax++;
  203. continue;
  204. }
  205. p2.GeomP = u.GeomP;
  206. ax++;
  207. }
  208. ax = x - 1;
  209. while (ax >= 0)
  210. {
  211. GeomPolyVal p2 = ps[(int)ax, y];
  212. if (p2 == null || p2.GeomP != p.GeomP)
  213. {
  214. ax--;
  215. continue;
  216. }
  217. p2.GeomP = u.GeomP;
  218. ax--;
  219. }
  220. ret.Remove(p.GeomP);
  221. p.GeomP = u.GeomP;
  222. x = (int)((bi.Next().Elem().X - domain.LowerBound.X) / cellWidth) + 1;
  223. //x++; this was already commented out!
  224. }
  225. }
  226. polyList = ret.GetListOfElements();
  227. foreach (GeomPoly poly in polyList)
  228. {
  229. verticesList.Add(new Vertices(poly.Points.GetListOfElements()));
  230. }
  231. return verticesList;
  232. }
  233. #region Private Methods
  234. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  235. /** Linearly interpolate between (x0 to x1) given a value at these coordinates (v0 and v1)
  236. such as to approximate value(return) = 0
  237. **/
  238. private static int[] _lookMarch = {
  239. 0x00, 0xE0, 0x38, 0xD8, 0x0E, 0xEE, 0x36, 0xD6, 0x83, 0x63, 0xBB, 0x5B, 0x8D,
  240. 0x6D, 0xB5, 0x55
  241. };
  242. private static float Lerp(float x0, float x1, float v0, float v1)
  243. {
  244. float dv = v0 - v1;
  245. float t;
  246. if (dv * dv < Settings.Epsilon)
  247. t = 0.5f;
  248. else t = v0 / dv;
  249. return x0 + t * (x1 - x0);
  250. }
  251. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  252. /** Recursive linear interpolation for use in marching squares **/
  253. private static float Xlerp(float x0, float x1, float y, float v0, float v1, sbyte[,] f, int c)
  254. {
  255. float xm = Lerp(x0, x1, v0, v1);
  256. if (c == 0)
  257. return xm;
  258. sbyte vm = f[(int)xm, (int)y];
  259. if (v0 * vm < 0)
  260. return Xlerp(x0, xm, y, v0, vm, f, c - 1);
  261. return Xlerp(xm, x1, y, vm, v1, f, c - 1);
  262. }
  263. /** Recursive linear interpolation for use in marching squares **/
  264. private static float Ylerp(float y0, float y1, float x, float v0, float v1, sbyte[,] f, int c)
  265. {
  266. float ym = Lerp(y0, y1, v0, v1);
  267. if (c == 0)
  268. return ym;
  269. sbyte vm = f[(int)x, (int)ym];
  270. if (v0 * vm < 0)
  271. return Ylerp(y0, ym, x, v0, vm, f, c - 1);
  272. return Ylerp(ym, y1, x, vm, v1, f, c - 1);
  273. }
  274. /** Square value for use in marching squares **/
  275. private static float Square(float x)
  276. {
  277. return x * x;
  278. }
  279. private static float VecDsq(Vector2 a, Vector2 b)
  280. {
  281. Vector2 d = a - b;
  282. return d.X * d.X + d.Y * d.Y;
  283. }
  284. private static float VecCross(Vector2 a, Vector2 b)
  285. {
  286. return a.X * b.Y - a.Y * b.X;
  287. }
  288. /** Look-up table to relate polygon key with the vertices that should be used for
  289. the sub polygon in marching squares
  290. **/
  291. /** Perform a single celled marching square for for the given cell defined by (x0,y0) (x1,y1)
  292. using the function f for recursive interpolation, given the look-up table 'fs' of
  293. the values of 'f' at cell vertices with the result to be stored in 'poly' given the actual
  294. coordinates of 'ax' 'ay' in the marching squares mesh.
  295. **/
  296. private static int MarchSquare(sbyte[,] f, sbyte[,] fs, ref GeomPoly poly, int ax, int ay, float x0, float y0,
  297. float x1, float y1, int bin)
  298. {
  299. //key lookup
  300. int key = 0;
  301. sbyte v0 = fs[ax, ay];
  302. if (v0 < 0) key |= 8;
  303. sbyte v1 = fs[ax + 1, ay];
  304. if (v1 < 0) key |= 4;
  305. sbyte v2 = fs[ax + 1, ay + 1];
  306. if (v2 < 0) key |= 2;
  307. sbyte v3 = fs[ax, ay + 1];
  308. if (v3 < 0) key |= 1;
  309. int val = _lookMarch[key];
  310. if (val != 0)
  311. {
  312. CxFastListNode<Vector2> pi = null;
  313. for (int i = 0; i < 8; i++)
  314. {
  315. Vector2 p;
  316. if ((val & (1 << i)) != 0)
  317. {
  318. if (i == 7 && (val & 1) == 0)
  319. poly.Points.Add(p = new Vector2(x0, Ylerp(y0, y1, x0, v0, v3, f, bin)));
  320. else
  321. {
  322. if (i == 0) p = new Vector2(x0, y0);
  323. else if (i == 2) p = new Vector2(x1, y0);
  324. else if (i == 4) p = new Vector2(x1, y1);
  325. else if (i == 6) p = new Vector2(x0, y1);
  326. else if (i == 1) p = new Vector2(Xlerp(x0, x1, y0, v0, v1, f, bin), y0);
  327. else if (i == 5) p = new Vector2(Xlerp(x0, x1, y1, v3, v2, f, bin), y1);
  328. else if (i == 3) p = new Vector2(x1, Ylerp(y0, y1, x1, v1, v2, f, bin));
  329. else p = new Vector2(x0, Ylerp(y0, y1, x0, v0, v3, f, bin));
  330. pi = poly.Points.Insert(pi, p);
  331. }
  332. poly.Length++;
  333. }
  334. }
  335. //poly.simplify(float.Epsilon,float.Epsilon);
  336. }
  337. return key;
  338. }
  339. /** Used in polygon composition to composit polygons into scan lines
  340. Combining polya and polyb into one super-polygon stored in polya.
  341. **/
  342. private static void combLeft(ref GeomPoly polya, ref GeomPoly polyb)
  343. {
  344. CxFastList<Vector2> ap = polya.Points;
  345. CxFastList<Vector2> bp = polyb.Points;
  346. CxFastListNode<Vector2> ai = ap.Begin();
  347. CxFastListNode<Vector2> bi = bp.Begin();
  348. Vector2 b = bi.Elem();
  349. CxFastListNode<Vector2> prea = null;
  350. while (ai != ap.End())
  351. {
  352. Vector2 a = ai.Elem();
  353. if (VecDsq(a, b) < Settings.Epsilon)
  354. {
  355. //ignore shared vertex if parallel
  356. if (prea != null)
  357. {
  358. Vector2 a0 = prea.Elem();
  359. b = bi.Next().Elem();
  360. Vector2 u = a - a0;
  361. //vec_new(u); vec_sub(a.p.p, a0.p.p, u);
  362. Vector2 v = b - a;
  363. //vec_new(v); vec_sub(b.p.p, a.p.p, v);
  364. float dot = VecCross(u, v);
  365. if (dot * dot < Settings.Epsilon)
  366. {
  367. ap.Erase(prea, ai);
  368. polya.Length--;
  369. ai = prea;
  370. }
  371. }
  372. //insert polyb into polya
  373. bool fst = true;
  374. CxFastListNode<Vector2> preb = null;
  375. while (!bp.Empty())
  376. {
  377. Vector2 bb = bp.Front();
  378. bp.Pop();
  379. if (!fst && !bp.Empty())
  380. {
  381. ai = ap.Insert(ai, bb);
  382. polya.Length++;
  383. preb = ai;
  384. }
  385. fst = false;
  386. }
  387. //ignore shared vertex if parallel
  388. ai = ai.Next();
  389. Vector2 a1 = ai.Elem();
  390. ai = ai.Next();
  391. if (ai == ap.End()) ai = ap.Begin();
  392. Vector2 a2 = ai.Elem();
  393. Vector2 a00 = preb.Elem();
  394. Vector2 uu = a1 - a00;
  395. //vec_new(u); vec_sub(a1.p, a0.p, u);
  396. Vector2 vv = a2 - a1;
  397. //vec_new(v); vec_sub(a2.p, a1.p, v);
  398. float dot1 = VecCross(uu, vv);
  399. if (dot1 * dot1 < Settings.Epsilon)
  400. {
  401. ap.Erase(preb, preb.Next());
  402. polya.Length--;
  403. }
  404. return;
  405. }
  406. prea = ai;
  407. ai = ai.Next();
  408. }
  409. }
  410. #endregion
  411. #region CxFastList from nape physics
  412. #region Nested type: CxFastList
  413. /// <summary>
  414. /// Designed as a complete port of CxFastList from CxStd.
  415. /// </summary>
  416. internal class CxFastList<T>
  417. {
  418. // first node in the list
  419. private CxFastListNode<T> _head;
  420. private int _count;
  421. /// <summary>
  422. /// Iterator to start of list (O(1))
  423. /// </summary>
  424. public CxFastListNode<T> Begin()
  425. {
  426. return _head;
  427. }
  428. /// <summary>
  429. /// Iterator to end of list (O(1))
  430. /// </summary>
  431. public CxFastListNode<T> End()
  432. {
  433. return null;
  434. }
  435. /// <summary>
  436. /// Returns first element of list (O(1))
  437. /// </summary>
  438. public T Front()
  439. {
  440. return _head.Elem();
  441. }
  442. /// <summary>
  443. /// add object to list (O(1))
  444. /// </summary>
  445. public CxFastListNode<T> Add(T value)
  446. {
  447. CxFastListNode<T> newNode = new CxFastListNode<T>(value);
  448. if (_head == null)
  449. {
  450. newNode._next = null;
  451. _head = newNode;
  452. _count++;
  453. return newNode;
  454. }
  455. newNode._next = _head;
  456. _head = newNode;
  457. _count++;
  458. return newNode;
  459. }
  460. /// <summary>
  461. /// remove object from list, returns true if an element was removed (O(n))
  462. /// </summary>
  463. public bool Remove(T value)
  464. {
  465. CxFastListNode<T> head = _head;
  466. CxFastListNode<T> prev = _head;
  467. EqualityComparer<T> comparer = EqualityComparer<T>.Default;
  468. if (head != null)
  469. {
  470. if (value != null)
  471. {
  472. do
  473. {
  474. // if we are on the value to be removed
  475. if (comparer.Equals(head._elt, value))
  476. {
  477. // then we need to patch the list
  478. // check to see if we are removing the _head
  479. if (head == _head)
  480. {
  481. _head = head._next;
  482. _count--;
  483. return true;
  484. }
  485. else
  486. {
  487. // were not at the head
  488. prev._next = head._next;
  489. _count--;
  490. return true;
  491. }
  492. }
  493. // cache the current as the previous for the next go around
  494. prev = head;
  495. head = head._next;
  496. } while (head != null);
  497. }
  498. }
  499. return false;
  500. }
  501. /// <summary>
  502. /// pop element from head of list (O(1)) Note: this does not return the object popped!
  503. /// There is good reason to this, and it regards the Alloc list variants which guarantee
  504. /// objects are released to the object pool. You do not want to retrieve an element
  505. /// through pop or else that object may suddenly be used by another piece of code which
  506. /// retrieves it from the object pool.
  507. /// </summary>
  508. public CxFastListNode<T> Pop()
  509. {
  510. return Erase(null, _head);
  511. }
  512. /// <summary>
  513. /// insert object after 'node' returning an iterator to the inserted object.
  514. /// </summary>
  515. public CxFastListNode<T> Insert(CxFastListNode<T> node, T value)
  516. {
  517. if (node == null)
  518. {
  519. return Add(value);
  520. }
  521. CxFastListNode<T> newNode = new CxFastListNode<T>(value);
  522. CxFastListNode<T> nextNode = node._next;
  523. newNode._next = nextNode;
  524. node._next = newNode;
  525. _count++;
  526. return newNode;
  527. }
  528. /// <summary>
  529. /// removes the element pointed to by 'node' with 'prev' being the previous iterator,
  530. /// returning an iterator to the element following that of 'node' (O(1))
  531. /// </summary>
  532. public CxFastListNode<T> Erase(CxFastListNode<T> prev, CxFastListNode<T> node)
  533. {
  534. // cache the node after the node to be removed
  535. CxFastListNode<T> nextNode = node._next;
  536. if (prev != null)
  537. prev._next = nextNode;
  538. else if (_head != null)
  539. _head = _head._next;
  540. else
  541. return null;
  542. _count--;
  543. return nextNode;
  544. }
  545. /// <summary>
  546. /// whether the list is empty (O(1))
  547. /// </summary>
  548. public bool Empty()
  549. {
  550. if (_head == null)
  551. return true;
  552. return false;
  553. }
  554. /// <summary>
  555. /// computes size of list (O(n))
  556. /// </summary>
  557. public int Size()
  558. {
  559. CxFastListNode<T> i = Begin();
  560. int count = 0;
  561. do
  562. {
  563. count++;
  564. } while (i.Next() != null);
  565. return count;
  566. }
  567. /// <summary>
  568. /// empty the list (O(1) if CxMixList, O(n) otherwise)
  569. /// </summary>
  570. public void Clear()
  571. {
  572. CxFastListNode<T> head = _head;
  573. while (head != null)
  574. {
  575. CxFastListNode<T> node2 = head;
  576. head = head._next;
  577. node2._next = null;
  578. }
  579. _head = null;
  580. _count = 0;
  581. }
  582. /// <summary>
  583. /// returns true if 'value' is an element of the list (O(n))
  584. /// </summary>
  585. public bool Has(T value)
  586. {
  587. return (Find(value) != null);
  588. }
  589. // Non CxFastList Methods
  590. public CxFastListNode<T> Find(T value)
  591. {
  592. // start at head
  593. CxFastListNode<T> head = _head;
  594. EqualityComparer<T> comparer = EqualityComparer<T>.Default;
  595. if (head != null)
  596. {
  597. if (value != null)
  598. {
  599. do
  600. {
  601. if (comparer.Equals(head._elt, value))
  602. {
  603. return head;
  604. }
  605. head = head._next;
  606. } while (head != _head);
  607. }
  608. else
  609. {
  610. do
  611. {
  612. if (head._elt == null)
  613. {
  614. return head;
  615. }
  616. head = head._next;
  617. } while (head != _head);
  618. }
  619. }
  620. return null;
  621. }
  622. public List<T> GetListOfElements()
  623. {
  624. List<T> list = new List<T>();
  625. CxFastListNode<T> iter = Begin();
  626. if (iter != null)
  627. {
  628. do
  629. {
  630. list.Add(iter._elt);
  631. iter = iter._next;
  632. } while (iter != null);
  633. }
  634. return list;
  635. }
  636. }
  637. #endregion
  638. #region Nested type: CxFastListNode
  639. internal class CxFastListNode<T>
  640. {
  641. internal T _elt;
  642. internal CxFastListNode<T> _next;
  643. public CxFastListNode(T obj)
  644. {
  645. _elt = obj;
  646. }
  647. public T Elem()
  648. {
  649. return _elt;
  650. }
  651. public CxFastListNode<T> Next()
  652. {
  653. return _next;
  654. }
  655. }
  656. #endregion
  657. #endregion
  658. #region Internal Stuff
  659. #region Nested type: GeomPoly
  660. internal class GeomPoly
  661. {
  662. public int Length;
  663. public CxFastList<Vector2> Points;
  664. public GeomPoly()
  665. {
  666. Points = new CxFastList<Vector2>();
  667. Length = 0;
  668. }
  669. }
  670. #endregion
  671. #region Nested type: GeomPolyVal
  672. private class GeomPolyVal
  673. {
  674. /** Associated polygon at coordinate **/
  675. /** Key of original sub-polygon **/
  676. public int Key;
  677. public GeomPoly GeomP;
  678. public GeomPolyVal(GeomPoly geomP, int K)
  679. {
  680. GeomP = geomP;
  681. Key = K;
  682. }
  683. }
  684. #endregion
  685. #endregion
  686. }
  687. }