SimpleSurfaceEdge.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /****************************************************************************
  2. Copyright (c) 2013, Jonathan Cecil and UCLA Game Lab
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6. 1. Redistributions of source code must retain the above copyright notice, this
  7. list of conditions and the following disclaimer.
  8. 2. Redistributions in binary form must reproduce the above copyright notice,
  9. this list of conditions and the following disclaimer in the documentation
  10. and/or other materials provided with the distribution.
  11. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  12. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  13. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  14. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  15. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  16. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  17. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  18. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  19. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  20. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  21. *****************************************************************************/
  22. using UnityEngine;
  23. using System.Collections;
  24. /***
  25. * MC_SimpleSurfaceEdge
  26. * class to read pixel data and create outline edges around opaque pixel areas.
  27. *
  28. ***/
  29. class MC_SimpleSurfaceEdge {
  30. private const float versionNumber = 0.7f;
  31. Color[] pixels; // the original pixel data from the image
  32. int imageHeight;
  33. int imageWidth;
  34. ArrayList edges;
  35. ArrayList vertices;
  36. ArrayList edgeLoops;
  37. public MC_SimpleSurfaceEdge(Color[] _pixels, int _imageWidth, int _imageHeight, float threshold) {
  38. pixels = _pixels;
  39. imageWidth = _imageWidth;
  40. imageHeight = _imageHeight;
  41. edges = new ArrayList();
  42. vertices = new ArrayList();
  43. edgeLoops = new ArrayList();
  44. float uvWidth = (float)imageWidth;
  45. float uvHeight = (float)imageHeight;
  46. for (int x = 0; x < imageWidth; x++) {
  47. float uvX = x + 0.5f;
  48. for (int y = 0; y < imageHeight; y++) {
  49. float uvY = y+0.5f;
  50. // get the first pixel
  51. Color pixel = pixels[x + (imageWidth * y)];
  52. float pixelAlpha = pixel.a;
  53. // only continue if the current pixel is opaque
  54. if (pixelAlpha < threshold) continue;
  55. // set up values for other possible pixel values
  56. float pixelAboveAlpha = 0.0f;
  57. float pixelBelowAlpha = 0.0f;
  58. float pixelRightAlpha = 0.0f;
  59. float pixelLeftAlpha = 0.0f;
  60. float pixelAboveRightAlpha = 0.0f;
  61. float pixelAboveLeftAlpha = 0.0f;
  62. float pixelBelowRightAlpha = 0.0f;
  63. // check x area, then the y.
  64. if ( x > 0 && x < imageWidth-1) {
  65. if ( y > 0 && y < imageHeight -1 ) {
  66. Color pixelAbove = pixels[x + (imageWidth * (y+1))];
  67. pixelAboveAlpha = pixelAbove.a;
  68. Color pixelBelow = pixels[x + (imageWidth * (y-1))];
  69. pixelBelowAlpha = pixelBelow.a;
  70. Color pixelRight = pixels[x + 1 + (imageWidth * y)];
  71. pixelRightAlpha = pixelRight.a;
  72. Color pixelLeft = pixels[x - 1 + (imageWidth * y)];
  73. pixelLeftAlpha = pixelLeft.a;
  74. Color pixelAboveRight = pixels[x + 1 + (imageWidth * (y + 1))];
  75. pixelAboveRightAlpha = pixelAboveRight.a;
  76. Color pixelAboveLeft = pixels[x - 1 + (imageWidth * (y + 1))];
  77. pixelAboveLeftAlpha = pixelAboveLeft.a;
  78. Color pixelBelowRight = pixels[x + 1 + (imageWidth * (y - 1))];
  79. pixelBelowRightAlpha = pixelBelowRight.a;
  80. }
  81. else if ( y == 0) {
  82. Color pixelAbove = pixels[x + (imageWidth * (y+1))];
  83. pixelAboveAlpha = pixelAbove.a;
  84. Color pixelRight = pixels[x + 1 + (imageWidth * y)];
  85. pixelRightAlpha = pixelRight.a;
  86. Color pixelLeft = pixels[x - 1 + (imageWidth * y)];
  87. pixelLeftAlpha = pixelLeft.a;
  88. Color pixelAboveRight = pixels[x + 1 + (imageWidth * (y + 1))];
  89. pixelAboveRightAlpha = pixelAboveRight.a;
  90. Color pixelAboveLeft = pixels[x - 1 + (imageWidth * (y + 1))];
  91. pixelAboveLeftAlpha = pixelAboveLeft.a;
  92. }
  93. else if ( y == imageHeight -1 ) {
  94. Color pixelBelow = pixels[x + (imageWidth * (y-1))];
  95. pixelBelowAlpha = pixelBelow.a;
  96. Color pixelRight = pixels[x + 1 + (imageWidth * y)];
  97. pixelRightAlpha = pixelRight.a;
  98. Color pixelLeft = pixels[x - 1 + (imageWidth * y)];
  99. pixelLeftAlpha = pixelLeft.a;
  100. Color pixelBelowRight = pixels[x + 1 + (imageWidth * (y - 1))];
  101. pixelBelowRightAlpha = pixelBelowRight.a;
  102. }
  103. else {
  104. Debug.Log("SimpleSurfaceEdge:: error constructing pixel values, misinterpreted y values. Please create a new issue at https://github.com/uclagamelab/MeshCreator/issues.");
  105. }
  106. }
  107. else if ( x == 0 ) {
  108. if ( y > 0 && y < imageHeight - 1) {
  109. Color pixelAbove = pixels[x + (imageWidth * (y+1))];
  110. pixelAboveAlpha = pixelAbove.a;
  111. Color pixelBelow = pixels[x + (imageWidth * (y-1))];
  112. pixelBelowAlpha = pixelBelow.a;
  113. Color pixelRight = pixels[x + 1 + (imageWidth * y)];
  114. pixelRightAlpha = pixelRight.a;
  115. Color pixelAboveRight = pixels[x + 1 + (imageWidth * (y + 1))];
  116. pixelAboveRightAlpha = pixelAboveRight.a;
  117. Color pixelBelowRight = pixels[x + 1 + (imageWidth * (y - 1))];
  118. pixelBelowRightAlpha = pixelBelowRight.a;
  119. }
  120. else if ( y == 0) {
  121. Color pixelAbove = pixels[x + (imageWidth * (y+1))];
  122. pixelAboveAlpha = pixelAbove.a;
  123. Color pixelRight = pixels[x + 1 + (imageWidth * y)];
  124. pixelRightAlpha = pixelRight.a;
  125. Color pixelAboveRight = pixels[x + 1 + (imageWidth * (y + 1))];
  126. pixelAboveRightAlpha = pixelAboveRight.a;
  127. }
  128. else if ( y == imageHeight -1 ) {
  129. Color pixelBelow = pixels[x + (imageWidth * (y-1))];
  130. pixelBelowAlpha = pixelBelow.a;
  131. Color pixelRight = pixels[x + 1 + (imageWidth * y)];
  132. pixelRightAlpha = pixelRight.a;
  133. Color pixelBelowRight = pixels[x + 1 + (imageWidth * (y - 1))];
  134. pixelBelowRightAlpha = pixelBelowRight.a;
  135. }
  136. else {
  137. Debug.Log("SimpleSurfaceEdge:: error constructing pixel values, misinterpreted y values. Please create a new issue at https://github.com/uclagamelab/MeshCreator/issues.");
  138. }
  139. }
  140. else if ( x == imageWidth -1 ) {
  141. if ( y > 0 && y < imageHeight -1 ) {
  142. Color pixelAbove = pixels[x + (imageWidth * (y+1))];
  143. pixelAboveAlpha = pixelAbove.a;
  144. Color pixelBelow = pixels[x + (imageWidth * (y-1))];
  145. pixelBelowAlpha = pixelBelow.a;
  146. Color pixelLeft = pixels[x - 1 + (imageWidth * y)];
  147. pixelLeftAlpha = pixelLeft.a;
  148. Color pixelAboveLeft = pixels[x - 1 + (imageWidth * (y + 1))];
  149. pixelAboveLeftAlpha = pixelAboveLeft.a;
  150. }
  151. else if ( y == 0) {
  152. Color pixelAbove = pixels[x + (imageWidth * (y+1))];
  153. pixelAboveAlpha = pixelAbove.a;
  154. Color pixelLeft = pixels[x - 1 + (imageWidth * y)];
  155. pixelLeftAlpha = pixelLeft.a;
  156. Color pixelAboveLeft = pixels[x - 1 + (imageWidth * (y + 1))];
  157. pixelAboveLeftAlpha = pixelAboveLeft.a;
  158. }
  159. else if ( y == imageHeight -1 ) {
  160. Color pixelBelow = pixels[x + (imageWidth * (y-1))];
  161. pixelBelowAlpha = pixelBelow.a;
  162. Color pixelLeft = pixels[x - 1 + (imageWidth * y)];
  163. pixelLeftAlpha = pixelLeft.a;
  164. }
  165. else {
  166. Debug.Log("SimpleSurfaceEdge:: error constructing pixel values, misinterpreted y values. Please create a new issue at https://github.com/uclagamelab/MeshCreator/issues.");
  167. }
  168. }
  169. // try the up facing case
  170. if (pixelAlpha >= threshold && pixelAboveAlpha >= threshold) {
  171. if (pixelAboveRightAlpha < threshold && pixelRightAlpha < threshold) {
  172. if (pixelAboveLeftAlpha >= threshold || pixelLeftAlpha >= threshold) {
  173. // add the vertical edge
  174. MC_Edge e = new MC_Edge(GetVertex(x,y,uvX/uvWidth,uvY/uvHeight), GetVertex(x,y+1,uvX/uvWidth,(uvY+1)/uvHeight));
  175. edges.Add(e);
  176. }
  177. }
  178. else if ( pixelAboveLeftAlpha < threshold && pixelLeftAlpha < threshold) {
  179. if (pixelAboveRightAlpha >= threshold || pixelRightAlpha >= threshold) {
  180. // add the vertical edge
  181. MC_Edge e = new MC_Edge(GetVertex(x,y,uvX/uvWidth,uvY/uvHeight), GetVertex(x,y+1,uvX/uvWidth,(uvY+1)/uvHeight));
  182. edges.Add(e);
  183. }
  184. }
  185. }
  186. // try the up diagonal case
  187. if (pixelAlpha >= threshold && pixelAboveRightAlpha >= threshold) {
  188. if (pixelAboveAlpha < threshold && pixelRightAlpha >= threshold) {
  189. // add the up diagonal edge
  190. MC_Edge e = new MC_Edge(GetVertex(x,y,uvX/uvWidth,uvY/uvHeight), GetVertex(x+1,y+1,(uvX+1)/uvWidth,(uvY+1)/uvHeight));
  191. edges.Add(e);
  192. }
  193. else if (pixelAboveAlpha >= threshold && pixelRightAlpha < threshold) {
  194. // add the up diagonal edge
  195. MC_Edge e = new MC_Edge(GetVertex(x,y,uvX/uvWidth,uvY/uvHeight), GetVertex(x+1,y+1,(uvX+1)/uvWidth,(uvY+1)/uvHeight));
  196. edges.Add(e);
  197. }
  198. }
  199. // try the right facing case
  200. if (pixelAlpha >= threshold && pixelRightAlpha >= threshold) {
  201. if (pixelAboveAlpha < threshold && pixelAboveRightAlpha < threshold) {
  202. if (pixelBelowAlpha >= threshold || pixelBelowRightAlpha >= threshold) {
  203. // add the horizontal edge
  204. MC_Edge e = new MC_Edge(GetVertex(x,y,uvX/uvWidth,uvY/uvHeight), GetVertex(x+1,y,(uvX+1)/uvWidth,uvY/uvHeight));
  205. edges.Add(e);
  206. }
  207. }
  208. else if ( pixelBelowAlpha < threshold && pixelBelowRightAlpha < threshold) {
  209. if (pixelAboveAlpha >= threshold || pixelAboveRightAlpha >= threshold) {
  210. // add the horizontal edge
  211. MC_Edge e = new MC_Edge(GetVertex(x,y,uvX/uvWidth,uvY/uvHeight), GetVertex(x+1,y,(uvX+1)/uvWidth,uvY/uvHeight));
  212. edges.Add(e);
  213. }
  214. }
  215. }
  216. // try the down diagonal case
  217. if (pixelAlpha >= threshold && pixelBelowRightAlpha >= threshold) {
  218. if ( pixelRightAlpha < threshold && pixelBelowAlpha >= threshold) {
  219. // add the down diagonal edge
  220. MC_Edge e = new MC_Edge(GetVertex(x,y,uvX/uvWidth,uvY/uvHeight), GetVertex(x+1,y-1,(uvX+1)/uvWidth,(uvY-1)/uvHeight));
  221. edges.Add(e);
  222. }
  223. else if (pixelRightAlpha >= threshold && pixelBelowAlpha < threshold) {
  224. // ad the down diagonal edge
  225. MC_Edge e = new MC_Edge(GetVertex(x,y,uvX/uvWidth,uvY/uvHeight), GetVertex(x+1,y-1,(uvX+1)/uvWidth,(uvY-1)/uvHeight));
  226. edges.Add(e);
  227. }
  228. }
  229. }
  230. }
  231. MakeOutsideEdge();
  232. SimplifyEdge();
  233. }
  234. MC_Vertex GetVertex(float x, float y, float u, float v) {
  235. for (int i = 0; i < vertices.Count; i++) {
  236. MC_Vertex ver = (MC_Vertex) vertices[i];
  237. if (ver.x == x && ver.y == y) {
  238. return ver;
  239. }
  240. }
  241. MC_Vertex newver = new MC_Vertex(x,y,u,v);
  242. vertices.Add(newver);
  243. return newver;
  244. }
  245. public void MergeClosePoints(float mergeDistance)
  246. {
  247. foreach (MC_EdgeLoop edgeLoop in edgeLoops)
  248. {
  249. edgeLoop.MergeClosePoints(mergeDistance);
  250. }
  251. }
  252. void SimplifyEdge() {
  253. foreach (MC_EdgeLoop edgeLoop in edgeLoops) {
  254. edgeLoop.SimplifyEdge();
  255. }
  256. }
  257. void MakeOutsideEdge() {
  258. // order the edges
  259. // start first edge loop with the first outside edge
  260. MC_EdgeLoop currentEdgeLoop = new MC_EdgeLoop((MC_Edge)edges[0]);
  261. edges.RemoveAt(0);
  262. edgeLoops.Add(currentEdgeLoop);
  263. while (edges.Count > 0) {
  264. // if the currentEdgeLoop is fully closed make a new edge loop
  265. if (currentEdgeLoop.IsClosed()) {
  266. MC_EdgeLoop nextEdgeLoop = new MC_EdgeLoop((MC_Edge)edges[0]);
  267. //Debug.LogWarning("SimpleSurfaceEdge::MakeOutsideEdge: adding another edge loop, last one was " + currentEdgeLoop.orderedEdges.Count + " edges long");
  268. //Debug.LogWarning(" this means your image has islands, I hope that's what you want.");
  269. edges.RemoveAt(0);
  270. edgeLoops.Add(nextEdgeLoop);
  271. currentEdgeLoop = nextEdgeLoop;
  272. }
  273. // test each edge to see if it fits into the edgeloop
  274. ArrayList deleteEdges = new ArrayList();
  275. for (int i = 0; i < edges.Count; i++) {
  276. MC_Edge e = (MC_Edge) edges[i];
  277. if (currentEdgeLoop.AddEdge(e)) { // try to add the edge
  278. deleteEdges.Add(e);
  279. }
  280. }
  281. // delete the added edges
  282. for (int i = 0; i < deleteEdges.Count; i++) {
  283. edges.Remove( (MC_Edge)deleteEdges[i] );
  284. }
  285. }
  286. }
  287. public Vector2[] GetOutsideEdgeVertices() {
  288. MC_EdgeLoop eL = (MC_EdgeLoop) edgeLoops[0];
  289. return eL.GetVertexList();
  290. }
  291. public ArrayList GetAllEdgeVertices() {
  292. ArrayList edgeLoopVertices = new ArrayList();
  293. foreach (MC_EdgeLoop el in edgeLoops) {
  294. edgeLoopVertices.Add(el.GetVertexList());
  295. }
  296. return edgeLoopVertices;
  297. }
  298. public bool ContainsIslands() {
  299. if (edgeLoops.Count > 1) return true;
  300. return false;
  301. }
  302. public Vector2 GetUVForIndex(int loopIndex, int i) {
  303. MC_EdgeLoop eL = (MC_EdgeLoop) edgeLoops[loopIndex];
  304. return eL.GetUVForIndex(i);
  305. //return new Vector2(raw.x/((float)imageWidth), raw.y/((float)imageHeight));
  306. }
  307. public Vector2 GetUVForIndex(int i) {
  308. MC_EdgeLoop eL = (MC_EdgeLoop) edgeLoops[0];
  309. return eL.GetUVForIndex(i);
  310. //return new Vector2(raw.x/((float)imageWidth), raw.y/((float)imageHeight));
  311. }
  312. }
  313. class MC_Vertex {
  314. public float x,y;
  315. public float u,v;
  316. public MC_Vertex(float _x, float _y, float _u, float _v) {
  317. x = _x;
  318. y = _y;
  319. u = _u;
  320. v = _v;
  321. }
  322. /*
  323. * GetString() returns a descriptive string about info in this object
  324. * Useful for debugging.
  325. */
  326. public string GetString() {
  327. return "Vertex(x,y:" + x + "," + y + ", uv:" + u + "," + v + ")";
  328. }
  329. }
  330. class MC_Edge {
  331. public MC_Vertex v1;
  332. public MC_Vertex v2;
  333. public bool isShared; // indicate if there are two of these?
  334. ArrayList attachedFaces;
  335. public MC_Edge(MC_Vertex _v1, MC_Vertex _v2) {
  336. v1 = _v1;
  337. v2 = _v2;
  338. isShared = false;
  339. attachedFaces = new ArrayList();
  340. }
  341. public void AttachFace(MC_Face f) {
  342. attachedFaces.Add(f);
  343. }
  344. public bool OtherFaceCentered(MC_Face f) {
  345. if (attachedFaces.Count > 1) {
  346. MC_Face face1 = (MC_Face) attachedFaces[0];
  347. MC_Face face2 = (MC_Face) attachedFaces[1];
  348. if ( face1 == null && face2 == f) return true; // faces already deleted????
  349. else if ( face2 == null && face1 == f) return true;
  350. else if ( face1 != null && face1 != f && face1.IsCentered()) return true;
  351. else if ( face2 != null && face2 != f && face2.IsCentered()) return true;
  352. }
  353. return false;
  354. }
  355. public void SwitchVertices() {
  356. MC_Vertex hold = v1;
  357. v1 = v2;
  358. v2 = hold;
  359. }
  360. /*
  361. * GetString() returns a descriptive string about info in this object
  362. * Useful for debugging.
  363. */
  364. public string GetString() {
  365. return "Edge (" + v1.GetString() + ", " + v2.GetString() + ", shared:" + isShared + ")";
  366. }
  367. }
  368. class MC_Face {
  369. public MC_Vertex v1, v2, v3;
  370. public MC_Edge e1, e2, e3;
  371. public MC_Face(MC_Edge _e1, MC_Edge _e2, MC_Edge _e3) {
  372. e1 = _e1;
  373. e2 = _e2;
  374. e3 = _e3;
  375. e1.AttachFace(this);
  376. e2.AttachFace(this);
  377. e3.AttachFace(this);
  378. v1 = e1.v1;
  379. v2 = e1.v2;
  380. if (e2.v1 != v1 && e2.v1 != v2) v3 = e2.v1;
  381. else v3 = e2.v2;
  382. }
  383. public bool ContainsEdge(MC_Edge e) {
  384. if (e1 == e || e2 == e || e3 == e) {
  385. return true;
  386. }
  387. return false;
  388. }
  389. public bool IsCentered() {
  390. if (e1.isShared && e2.isShared && e3.isShared) {
  391. return true;
  392. }
  393. return false;
  394. }
  395. public bool IsCenteredCentered() {
  396. if (IsCentered()) {
  397. if (e1.OtherFaceCentered(this) && e2.OtherFaceCentered(this) && e3.OtherFaceCentered(this) ) {
  398. return true;
  399. }
  400. }
  401. return false;
  402. }
  403. public MC_Vertex[] GetVertices() {
  404. return new MC_Vertex[] { v1, v2, v3};
  405. }
  406. }
  407. // ordered list of edges
  408. class MC_EdgeLoop {
  409. public ArrayList orderedEdges;
  410. public MC_EdgeLoop(MC_Edge e) {
  411. orderedEdges = new ArrayList();
  412. orderedEdges.Add(e);
  413. }
  414. public bool AddEdge(MC_Edge e) {
  415. // see if it shares with the last edge
  416. MC_Vertex lastVertex = ((MC_Edge) orderedEdges[orderedEdges.Count-1]).v2;
  417. if (e.v1 == lastVertex) { // this is the correct vertex order
  418. orderedEdges.Add(e);
  419. return true;
  420. }
  421. else if (e.v2 == lastVertex) { // incorrect order, switch before adding
  422. e.SwitchVertices();
  423. orderedEdges.Add(e);
  424. return true;
  425. }
  426. // see if it shares with the first edge
  427. MC_Vertex firstVertex = ((MC_Edge) orderedEdges[0]).v1;
  428. if (e.v2 == firstVertex) { // this is the correct vertex order
  429. orderedEdges.Insert(0,e);
  430. return true;
  431. }
  432. else if (e.v1 == firstVertex) { // incorrect order, switch before adding
  433. e.SwitchVertices();
  434. orderedEdges.Insert(0, e);
  435. return true;
  436. }
  437. return false;
  438. }
  439. public bool IsClosed() {
  440. if (orderedEdges.Count < 2) return false;
  441. MC_Vertex lastVertex = ((MC_Edge) orderedEdges[orderedEdges.Count-1]).v2;
  442. MC_Vertex firstVertex = ((MC_Edge) orderedEdges[0]).v1;
  443. if (firstVertex.x == lastVertex.x && firstVertex.y == lastVertex.y) return true;
  444. return false;
  445. }
  446. public Vector2[] GetVertexList() {
  447. Vector2[] verts = new Vector2[orderedEdges.Count];
  448. for (int i = 0; i < orderedEdges.Count; i++) {
  449. MC_Vertex v = ((MC_Edge) orderedEdges[i]).v1;
  450. verts[i]= new Vector2(v.x, v.y);
  451. }
  452. return verts;
  453. }
  454. public Vector2 GetUVForIndex(int i) {
  455. if (i >= orderedEdges.Count) {
  456. //Debug.Log("got " + i + " index for ordered edge with " + orderedEdges.Count + " elements");
  457. return new Vector2();
  458. }
  459. MC_Vertex v = ((MC_Edge)orderedEdges[i]).v1;
  460. return new Vector2(v.u, v.v);
  461. }
  462. /*
  463. * GetString() returns a descriptive string about info in this object
  464. * Useful for debugging.
  465. */
  466. public string GetString() {
  467. string s = "EdgeLoop with " + orderedEdges.Count + " edges: ";
  468. for (int i = 0; i < orderedEdges.Count; i++) {
  469. MC_Edge e = (MC_Edge) orderedEdges[i];
  470. s += e.GetString() + ", " ;
  471. }
  472. return s;
  473. }
  474. /*
  475. * SimplifyEdge() searchs for edges in which the shared vertex is a point
  476. * on a line between the two outer points.
  477. */
  478. public void SimplifyEdge() {
  479. ArrayList newOrderedEdges = new ArrayList(); // list to stick the joined edges
  480. MC_Edge currentEdge = (MC_Edge)orderedEdges[0];
  481. for (int i = 1; i < orderedEdges.Count; i++) { // start with the second edge for comparison
  482. MC_Edge testEdge = (MC_Edge) orderedEdges[i];
  483. MC_Vertex v1 = currentEdge.v1;
  484. MC_Vertex v2 = testEdge.v2;
  485. MC_Vertex sharedPoint = currentEdge.v2;
  486. if (sharedPoint != testEdge.v1) { // oops, bad list, it should be closed by now
  487. Debug.LogError("Mesh Creator EdgeLoop Error: list is not ordered when simplifying edge. Please create a new issue at https://github.com/uclagamelab/MeshCreator/issues.");
  488. return;
  489. }
  490. if (v1 == v2) {
  491. Debug.LogError("Mesh Creator EdgeLoop Error: found matching endpoints for a line when simplifying. Please create a new issue at https://github.com/uclagamelab/MeshCreator/issues.");
  492. return;
  493. }
  494. // determine if sharedPoint is on a line between the two endpoints
  495. //The point (x3, y3) is on the line determined by (x1, y1) and (x2, y2) if and only if (x3-x1)*(y2-y1)==(x2-x1)*(y3-y1).
  496. float slope1 = (sharedPoint.x - v1.x) * (v2.y-v1.y);
  497. float slope2 = (v2.x - v1.x) * (sharedPoint.y- v1.y);
  498. if (slope1 == slope2) { // combine the two lines into current
  499. currentEdge.v2 = v2;
  500. }
  501. else { // there isn't a continuation of line, so add current to new ordered and set current to testEdge
  502. newOrderedEdges.Add(currentEdge);
  503. currentEdge = testEdge;
  504. }
  505. }
  506. newOrderedEdges.Add(currentEdge);
  507. orderedEdges = newOrderedEdges;
  508. }
  509. // very simple edge smoothing by comparing distance between adjacent
  510. // points on edge and merging if close enough
  511. public void MergeClosePoints(float mergeDistance)
  512. {
  513. if (mergeDistance < 0.0f) return;
  514. ArrayList newOrderedEdges = new ArrayList(); // list to stick the joined edges
  515. //int originalCount = orderedEdges.Count;
  516. MC_Edge currentEdge = (MC_Edge)orderedEdges[0];
  517. for (int i = 1; i < orderedEdges.Count; i++) { // start with the second edge for comparison
  518. MC_Edge testEdge = (MC_Edge) orderedEdges[i];
  519. float dist = Vector2.Distance( new Vector2(currentEdge.v1.x, currentEdge.v1.y), new Vector2(testEdge.v2.x, testEdge.v2.y) );
  520. MC_Vertex v2 = testEdge.v2;
  521. if ( dist < mergeDistance ) { // combine the two lines into current
  522. currentEdge.v2 = v2;
  523. }
  524. else { // there isn't a continuation of line, so add current to new ordered and set current to testEdge
  525. newOrderedEdges.Add(currentEdge);
  526. currentEdge = testEdge;
  527. }
  528. }
  529. newOrderedEdges.Add(currentEdge);
  530. orderedEdges = newOrderedEdges;
  531. /*if (originalCount != orderedEdges.Count)
  532. {
  533. Debug.Log("SimpleSurfaceEdge::MergeClosePoints(): trimmed from " + originalCount + " to " + orderedEdges.Count + " edges.");
  534. }*/
  535. }
  536. }