par_msquares.h 80 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156
  1. // MSQUARES :: https://github.com/prideout/par
  2. // Converts fp32 grayscale images, or 8-bit color images, into triangles.
  3. //
  4. // THIS IS EXPERIMENTAL CODE, DO NOT USE IN PRODUCTION
  5. //
  6. // Note that a potentially more interesting project for converting bitmaps
  7. // into vectors can be found at https://github.com/BlockoS/blob, which is an
  8. // implementation of "A linear-time component-labeling algorithm using contour
  9. // tracing technique" by Fu Chang, Chun-Jen Chen, and Chi-Jen Lu. I recommend
  10. // using that in combination with a simple ear-clipping algorithm for triangle
  11. // tessellation. (see https://prideout.net/polygon.js)
  12. //
  13. // For grayscale images, a threshold is specified to determine insideness.
  14. // For color images, an exact color is specified to determine insideness.
  15. // Color images can be r8, rg16, rgb24, or rgba32. For a visual overview of
  16. // the API and all the flags, see:
  17. //
  18. // https://prideout.net/marching-squares
  19. //
  20. // Distributed under the MIT License, see bottom of file.
  21. #ifndef PAR_MSQUARES_H
  22. #define PAR_MSQUARES_H
  23. #ifdef __cplusplus
  24. extern "C" {
  25. #endif
  26. #include <stdint.h>
  27. // -----------------------------------------------------------------------------
  28. // BEGIN PUBLIC API
  29. // -----------------------------------------------------------------------------
  30. #ifndef PAR_MSQUARES_T
  31. #define PAR_MSQUARES_T uint16_t
  32. #endif
  33. typedef uint8_t par_byte;
  34. typedef struct par_msquares_meshlist_s par_msquares_meshlist;
  35. // Results of a marching squares operation. Triangles are counter-clockwise.
  36. typedef struct {
  37. float* points; // pointer to XY (or XYZ) vertex coordinates
  38. int npoints; // number of vertex coordinates
  39. PAR_MSQUARES_T* triangles; // pointer to 3-tuples of vertex indices
  40. int ntriangles; // number of 3-tuples
  41. int dim; // number of floats per point (either 2 or 3)
  42. uint32_t color; // used only with par_msquares_color_multi
  43. } par_msquares_mesh;
  44. // Polyline boundary extracted from a mesh, composed of one or more chains.
  45. // Counterclockwise chains are solid, clockwise chains are holes. So, when
  46. // serializing to SVG, all chains can be aggregated in a single <path>,
  47. // provided they each terminate with a "Z" and use the default fill rule.
  48. typedef struct {
  49. float* points; // list of XY vertex coordinates
  50. int npoints; // number of vertex coordinates
  51. float** chains; // list of pointers to the start of each chain
  52. PAR_MSQUARES_T* lengths; // list of chain lengths
  53. int nchains; // number of chains
  54. } par_msquares_boundary;
  55. // Reverses the "insideness" test.
  56. #define PAR_MSQUARES_INVERT (1 << 0)
  57. // Returns a meshlist with two meshes: one for the inside, one for the outside.
  58. #define PAR_MSQUARES_DUAL (1 << 1)
  59. // Requests that returned meshes have 3-tuple coordinates instead of 2-tuples.
  60. // When using a color-based function, the Z coordinate represents the alpha
  61. // value of the nearest pixel.
  62. #define PAR_MSQUARES_HEIGHTS (1 << 2)
  63. // Applies a step function to the Z coordinates. Requires HEIGHTS and DUAL.
  64. #define PAR_MSQUARES_SNAP (1 << 3)
  65. // Adds extrusion triangles to each mesh other than the lowest mesh. Requires
  66. // the PAR_MSQUARES_HEIGHTS flag to be present.
  67. #define PAR_MSQUARES_CONNECT (1 << 4)
  68. // Enables quick & dirty (not best) simpification of the returned mesh.
  69. #define PAR_MSQUARES_SIMPLIFY (1 << 5)
  70. // Indicates that the "color" argument is ABGR instead of ARGB.
  71. #define PAR_MSQUARES_SWIZZLE (1 << 6)
  72. // Ensures there are no T-junction vertices. (par_msquares_color_multi only)
  73. // Requires the PAR_MSQUARES_SIMPLIFY flag to be disabled.
  74. #define PAR_MSQUARES_CLEAN (1 << 7)
  75. par_msquares_meshlist* par_msquares_grayscale(float const* data, int width,
  76. int height, int cellsize, float threshold, int flags);
  77. par_msquares_meshlist* par_msquares_color(par_byte const* data, int width,
  78. int height, int cellsize, uint32_t color, int bpp, int flags);
  79. par_msquares_mesh const* par_msquares_get_mesh(par_msquares_meshlist*, int n);
  80. int par_msquares_get_count(par_msquares_meshlist*);
  81. void par_msquares_free(par_msquares_meshlist*);
  82. void par_msquares_free_boundary(par_msquares_boundary*);
  83. typedef int (*par_msquares_inside_fn)(int, void*);
  84. typedef float (*par_msquares_height_fn)(float, float, void*);
  85. par_msquares_meshlist* par_msquares_function(int width, int height,
  86. int cellsize, int flags, void* context, par_msquares_inside_fn insidefn,
  87. par_msquares_height_fn heightfn);
  88. par_msquares_meshlist* par_msquares_grayscale_multi(float const* data,
  89. int width, int height, int cellsize, float const* thresholds,
  90. int nthresholds, int flags);
  91. par_msquares_meshlist* par_msquares_color_multi(par_byte const* data, int width,
  92. int height, int cellsize, int bpp, int flags);
  93. par_msquares_boundary* par_msquares_extract_boundary(par_msquares_mesh const* );
  94. #ifndef PAR_PI
  95. #define PAR_PI (3.14159265359)
  96. #define PAR_MIN(a, b) (a > b ? b : a)
  97. #define PAR_MAX(a, b) (a > b ? a : b)
  98. #define PAR_CLAMP(v, lo, hi) PAR_MAX(lo, PAR_MIN(hi, v))
  99. #define PAR_SWAP(T, A, B) { T tmp = B; B = A; A = tmp; }
  100. #define PAR_SQR(a) ((a) * (a))
  101. #endif
  102. #ifndef PAR_MALLOC
  103. #define PAR_MALLOC(T, N) ((T*) malloc(N * sizeof(T)))
  104. #define PAR_CALLOC(T, N) ((T*) calloc(N * sizeof(T), 1))
  105. #define PAR_REALLOC(T, BUF, N) ((T*) realloc(BUF, sizeof(T) * (N)))
  106. #define PAR_FREE(BUF) free(BUF)
  107. #endif
  108. #ifdef __cplusplus
  109. }
  110. #endif
  111. // -----------------------------------------------------------------------------
  112. // END PUBLIC API
  113. // -----------------------------------------------------------------------------
  114. #ifdef PAR_MSQUARES_IMPLEMENTATION
  115. #include <stdlib.h>
  116. #include <assert.h>
  117. #include <float.h>
  118. #include <string.h>
  119. typedef struct {
  120. PAR_MSQUARES_T* values;
  121. size_t count;
  122. size_t capacity;
  123. } par__uint16list;
  124. typedef struct {
  125. float* points;
  126. int npoints;
  127. PAR_MSQUARES_T* triangles;
  128. int ntriangles;
  129. int dim;
  130. uint32_t color;
  131. int nconntriangles;
  132. PAR_MSQUARES_T* conntri;
  133. par__uint16list* tjunctions;
  134. } par_msquares__mesh;
  135. struct par_msquares_meshlist_s {
  136. int nmeshes;
  137. par_msquares__mesh** meshes;
  138. };
  139. static int** par_msquares_binary_point_table = 0;
  140. static int** par_msquares_binary_triangle_table = 0;
  141. static int* par_msquares_quaternary_triangle_table[64][4];
  142. static int* par_msquares_quaternary_boundary_table[64][4];
  143. static par_msquares_meshlist* par_msquares__merge(par_msquares_meshlist** lists,
  144. int count, int snap);
  145. static void par_init_tables()
  146. {
  147. char const* BINARY_TABLE =
  148. "0"
  149. "1017"
  150. "1123"
  151. "2023370"
  152. "1756"
  153. "2015560"
  154. "2123756"
  155. "3023035056"
  156. "1345"
  157. "4013034045057"
  158. "2124451"
  159. "3024045057"
  160. "2734467"
  161. "3013034046"
  162. "3124146167"
  163. "2024460";
  164. char const* binary_token = BINARY_TABLE;
  165. par_msquares_binary_point_table = PAR_CALLOC(int*, 16);
  166. par_msquares_binary_triangle_table = PAR_CALLOC(int*, 16);
  167. for (int i = 0; i < 16; i++) {
  168. int ntris = *binary_token - '0';
  169. binary_token++;
  170. par_msquares_binary_triangle_table[i] =
  171. PAR_CALLOC(int, (ntris + 1) * 3);
  172. int* sqrtris = par_msquares_binary_triangle_table[i];
  173. sqrtris[0] = ntris;
  174. int mask = 0;
  175. int* sqrpts = par_msquares_binary_point_table[i] = PAR_CALLOC(int, 7);
  176. sqrpts[0] = 0;
  177. for (int j = 0; j < ntris * 3; j++, binary_token++) {
  178. int midp = *binary_token - '0';
  179. int bit = 1 << midp;
  180. if (!(mask & bit)) {
  181. mask |= bit;
  182. sqrpts[++sqrpts[0]] = midp;
  183. }
  184. sqrtris[j + 1] = midp;
  185. }
  186. }
  187. char const* QUATERNARY_TABLE =
  188. "2024046000"
  189. "3346360301112300"
  190. "3346360301112300"
  191. "3346360301112300"
  192. "3560502523013450"
  193. "2015056212414500"
  194. "4018087785756212313828348450"
  195. "4018087785756212313828348450"
  196. "3560502523013450"
  197. "4018087785756212313828348450"
  198. "2015056212414500"
  199. "4018087785756212313828348450"
  200. "3560502523013450"
  201. "4018087785756212313828348450"
  202. "4018087785756212313828348450"
  203. "2015056212414500"
  204. "3702724745001756"
  205. "2018087212313828348452785756"
  206. "4013034045057112301756"
  207. "4013034045057112301756"
  208. "2023037027347460"
  209. "1701312414616700"
  210. "2018087212313847857568348450"
  211. "2018087212313847857568348450"
  212. "4018087123138028348452785756"
  213. "1701467161262363513450"
  214. "2018087412313883484502785756"
  215. "2018087212313828348452785756"
  216. "4018087123138028348452785756"
  217. "1701467161262363513450"
  218. "2018087212313828348452785756"
  219. "2018087412313883484502785756"
  220. "3702724745001756"
  221. "4013034045057112301756"
  222. "2018087212313828348452785756"
  223. "4013034045057112301756"
  224. "4018087123138028348452785756"
  225. "2018087412313883484502785756"
  226. "1701467161262363513450"
  227. "2018087212313828348452785756"
  228. "2023037027347460"
  229. "2018087212313847857568348450"
  230. "1701312414616700"
  231. "2018087212313847857568348450"
  232. "4018087123138028348452785756"
  233. "2018087212313828348452785756"
  234. "1701467161262363513450"
  235. "2018087412313883484502785756"
  236. "3702724745001756"
  237. "4013034045057112301756"
  238. "4013034045057112301756"
  239. "2018087212313828348452785756"
  240. "4018087123138028348452785756"
  241. "2018087412313883484502785756"
  242. "2018087212313828348452785756"
  243. "1701467161262363513450"
  244. "4018087123138028348452785756"
  245. "2018087212313828348452785756"
  246. "2018087412313883484502785756"
  247. "1701467161262363513450"
  248. "2023037027347460"
  249. "2018087212313847857568348450"
  250. "2018087212313847857568348450"
  251. "1701312414616700";
  252. char const* quaternary_token = QUATERNARY_TABLE;
  253. int* quaternary_values = PAR_CALLOC(int, strlen(QUATERNARY_TABLE));
  254. int* vals = quaternary_values;
  255. for (int i = 0; i < 64; i++) {
  256. int ntris = *quaternary_token++ - '0';
  257. *vals = ntris;
  258. par_msquares_quaternary_triangle_table[i][0] = vals++;
  259. for (int j = 0; j < ntris * 3; j++) {
  260. int pt = *quaternary_token++ - '0';
  261. assert(pt >= 0 && pt < 9);
  262. *vals++ = pt;
  263. }
  264. ntris = *quaternary_token++ - '0';
  265. *vals = ntris;
  266. par_msquares_quaternary_triangle_table[i][1] = vals++;
  267. for (int j = 0; j < ntris * 3; j++) {
  268. int pt = *quaternary_token++ - '0';
  269. assert(pt >= 0 && pt < 9);
  270. *vals++ = pt;
  271. }
  272. ntris = *quaternary_token++ - '0';
  273. *vals = ntris;
  274. par_msquares_quaternary_triangle_table[i][2] = vals++;
  275. for (int j = 0; j < ntris * 3; j++) {
  276. int pt = *quaternary_token++ - '0';
  277. assert(pt >= 0 && pt < 9);
  278. *vals++ = pt;
  279. }
  280. ntris = *quaternary_token++ - '0';
  281. *vals = ntris;
  282. par_msquares_quaternary_triangle_table[i][3] = vals++;
  283. for (int j = 0; j < ntris * 3; j++) {
  284. int pt = *quaternary_token++ - '0';
  285. assert(pt >= 0 && pt < 9);
  286. *vals++ = pt;
  287. }
  288. }
  289. assert(vals == quaternary_values + strlen(QUATERNARY_TABLE));
  290. char const* QUATERNARY_EDGES =
  291. "0000"
  292. "11313100113131001131310013501530"
  293. "115151002188523881258830218852388125883013501530"
  294. "218852388125883011515100218852388125883013501530"
  295. "218852388125883021885238812588301151510015700175"
  296. "2188723881258832788521357131017521357131017513701730"
  297. "11717100218872388127883021887238812788302388702588327885"
  298. "1172713515302188725881027885218872388125883278852388702588327885"
  299. "11727135153021887238812588327885218872588102788515700175"
  300. "213571310175218872388125883278852135713101752388702588327885"
  301. "21887258810278851172713515302188723881258832788513701730"
  302. "21887238812788301171710021887238812788302388702588327885"
  303. "21887238812588327885117271351530218872588102788515700175"
  304. "213571310175213571310175218872388125883278852388702588327885"
  305. "2188725881027885218872388125883278851172713515302388702588327885"
  306. "21887238812588327885218872588102788511727135153013701730"
  307. "2188723881278830218872388127883011717100";
  308. quaternary_token = QUATERNARY_EDGES;
  309. quaternary_values = PAR_CALLOC(int, strlen(QUATERNARY_EDGES));
  310. vals = quaternary_values;
  311. for (int i = 0; i < 64; i++) {
  312. int nedges = *quaternary_token++ - '0';
  313. *vals = nedges;
  314. par_msquares_quaternary_boundary_table[i][0] = vals++;
  315. for (int j = 0; j < nedges * 2; j++) {
  316. int pt = *quaternary_token++ - '0';
  317. assert(pt >= 0 && pt < 9);
  318. *vals++ = pt;
  319. }
  320. nedges = *quaternary_token++ - '0';
  321. *vals = nedges;
  322. par_msquares_quaternary_boundary_table[i][1] = vals++;
  323. for (int j = 0; j < nedges * 2; j++) {
  324. int pt = *quaternary_token++ - '0';
  325. assert(pt >= 0 && pt < 9);
  326. *vals++ = pt;
  327. }
  328. nedges = *quaternary_token++ - '0';
  329. *vals = nedges;
  330. par_msquares_quaternary_boundary_table[i][2] = vals++;
  331. for (int j = 0; j < nedges * 2; j++) {
  332. int pt = *quaternary_token++ - '0';
  333. assert(pt >= 0 && pt < 9);
  334. *vals++ = pt;
  335. }
  336. nedges = *quaternary_token++ - '0';
  337. *vals = nedges;
  338. par_msquares_quaternary_boundary_table[i][3] = vals++;
  339. for (int j = 0; j < nedges * 2; j++) {
  340. int pt = *quaternary_token++ - '0';
  341. assert(pt >= 0 && pt < 9);
  342. *vals++ = pt;
  343. }
  344. }
  345. assert(vals == quaternary_values + strlen(QUATERNARY_EDGES));
  346. }
  347. typedef struct {
  348. float const* data;
  349. float threshold;
  350. float lower_bound;
  351. float upper_bound;
  352. int width;
  353. int height;
  354. } par_gray_context;
  355. static int gray_inside(int location, void* contextptr)
  356. {
  357. par_gray_context* context = (par_gray_context*) contextptr;
  358. return context->data[location] > context->threshold;
  359. }
  360. static int gray_multi_inside(int location, void* contextptr)
  361. {
  362. par_gray_context* context = (par_gray_context*) contextptr;
  363. float val = context->data[location];
  364. float upper = context->upper_bound;
  365. float lower = context->lower_bound;
  366. return val >= lower && val < upper;
  367. }
  368. static float gray_height(float x, float y, void* contextptr)
  369. {
  370. par_gray_context* context = (par_gray_context*) contextptr;
  371. int i = PAR_CLAMP(context->width * x, 0, context->width - 1);
  372. int j = PAR_CLAMP(context->height * y, 0, context->height - 1);
  373. return context->data[i + j * context->width];
  374. }
  375. typedef struct {
  376. par_byte const* data;
  377. par_byte color[4];
  378. int bpp;
  379. int width;
  380. int height;
  381. } par_color_context;
  382. static int color_inside(int location, void* contextptr)
  383. {
  384. par_color_context* context = (par_color_context*) contextptr;
  385. par_byte const* data = context->data + location * context->bpp;
  386. for (int i = 0; i < context->bpp; i++) {
  387. if (data[i] != context->color[i]) {
  388. return 0;
  389. }
  390. }
  391. return 1;
  392. }
  393. static float color_height(float x, float y, void* contextptr)
  394. {
  395. par_color_context* context = (par_color_context*) contextptr;
  396. assert(context->bpp == 4);
  397. int i = PAR_CLAMP(context->width * x, 0, context->width - 1);
  398. int j = PAR_CLAMP(context->height * y, 0, context->height - 1);
  399. int k = i + j * context->width;
  400. return context->data[k * 4 + 3] / 255.0;
  401. }
  402. par_msquares_meshlist* par_msquares_color(par_byte const* data, int width,
  403. int height, int cellsize, uint32_t color, int bpp, int flags)
  404. {
  405. par_color_context context;
  406. context.bpp = bpp;
  407. if (flags & PAR_MSQUARES_SWIZZLE) {
  408. context.color[0] = (color >> 0) & 0xff;
  409. context.color[1] = (color >> 8) & 0xff;
  410. context.color[2] = (color >> 16) & 0xff;
  411. context.color[3] = (color >> 24) & 0xff;
  412. } else {
  413. context.color[0] = (color >> 16) & 0xff;
  414. context.color[1] = (color >> 8) & 0xff;
  415. context.color[2] = (color >> 0) & 0xff;
  416. context.color[3] = (color >> 24) & 0xff;
  417. }
  418. context.data = data;
  419. context.width = width;
  420. context.height = height;
  421. return par_msquares_function(
  422. width, height, cellsize, flags, &context, color_inside, color_height);
  423. }
  424. par_msquares_meshlist* par_msquares_grayscale(float const* data, int width,
  425. int height, int cellsize, float threshold, int flags)
  426. {
  427. par_gray_context context;
  428. context.width = width;
  429. context.height = height;
  430. context.data = data;
  431. context.threshold = threshold;
  432. return par_msquares_function(
  433. width, height, cellsize, flags, &context, gray_inside, gray_height);
  434. }
  435. par_msquares_meshlist* par_msquares_grayscale_multi(float const* data,
  436. int width, int height, int cellsize, float const* thresholds,
  437. int nthresholds, int flags)
  438. {
  439. par_msquares_meshlist* mlists[2];
  440. mlists[0] = PAR_CALLOC(par_msquares_meshlist, 1);
  441. int connect = flags & PAR_MSQUARES_CONNECT;
  442. int snap = flags & PAR_MSQUARES_SNAP;
  443. int heights = flags & PAR_MSQUARES_HEIGHTS;
  444. if (!heights) {
  445. snap = connect = 0;
  446. }
  447. flags &= ~PAR_MSQUARES_INVERT;
  448. flags &= ~PAR_MSQUARES_DUAL;
  449. flags &= ~PAR_MSQUARES_CONNECT;
  450. flags &= ~PAR_MSQUARES_SNAP;
  451. par_gray_context context;
  452. context.width = width;
  453. context.height = height;
  454. context.data = data;
  455. context.lower_bound = -FLT_MAX;
  456. for (int i = 0; i <= nthresholds; i++) {
  457. int mergeconf = i > 0 ? connect : 0;
  458. if (i == nthresholds) {
  459. context.upper_bound = FLT_MAX;
  460. mergeconf |= snap;
  461. } else {
  462. context.upper_bound = thresholds[i];
  463. }
  464. mlists[1] = par_msquares_function(width, height, cellsize, flags,
  465. &context, gray_multi_inside, gray_height);
  466. mlists[0] = par_msquares__merge(mlists, 2, mergeconf);
  467. context.lower_bound = context.upper_bound;
  468. flags |= connect;
  469. }
  470. return mlists[0];
  471. }
  472. par_msquares_mesh const* par_msquares_get_mesh(
  473. par_msquares_meshlist* mlist, int mindex)
  474. {
  475. assert(mlist && mindex < mlist->nmeshes);
  476. return (par_msquares_mesh const*) mlist->meshes[mindex];
  477. }
  478. int par_msquares_get_count(par_msquares_meshlist* mlist)
  479. {
  480. assert(mlist);
  481. return mlist->nmeshes;
  482. }
  483. void par_msquares_free(par_msquares_meshlist* mlist)
  484. {
  485. if (!mlist) {
  486. return;
  487. }
  488. par_msquares__mesh** meshes = mlist->meshes;
  489. for (int i = 0; i < mlist->nmeshes; i++) {
  490. free(meshes[i]->points);
  491. free(meshes[i]->triangles);
  492. free(meshes[i]);
  493. }
  494. free(meshes);
  495. free(mlist);
  496. }
  497. // Combine multiple meshlists by moving mesh pointers, and optionally applying
  498. // a snap operation that assigns a single Z value across all verts in each
  499. // mesh. The Z value determined by the mesh's position in the final mesh list.
  500. static par_msquares_meshlist* par_msquares__merge(par_msquares_meshlist** lists,
  501. int count, int snap)
  502. {
  503. par_msquares_meshlist* merged = PAR_CALLOC(par_msquares_meshlist, 1);
  504. merged->nmeshes = 0;
  505. for (int i = 0; i < count; i++) {
  506. merged->nmeshes += lists[i]->nmeshes;
  507. }
  508. merged->meshes = PAR_CALLOC(par_msquares__mesh*, merged->nmeshes);
  509. par_msquares__mesh** pmesh = merged->meshes;
  510. for (int i = 0; i < count; i++) {
  511. par_msquares_meshlist* meshlist = lists[i];
  512. for (int j = 0; j < meshlist->nmeshes; j++) {
  513. *pmesh++ = meshlist->meshes[j];
  514. }
  515. free(meshlist);
  516. }
  517. if (!snap) {
  518. return merged;
  519. }
  520. pmesh = merged->meshes;
  521. float zmin = FLT_MAX;
  522. float zmax = -zmin;
  523. for (int i = 0; i < merged->nmeshes; i++, pmesh++) {
  524. float* pzed = (*pmesh)->points + 2;
  525. for (int j = 0; j < (*pmesh)->npoints; j++, pzed += 3) {
  526. zmin = PAR_MIN(*pzed, zmin);
  527. zmax = PAR_MAX(*pzed, zmax);
  528. }
  529. }
  530. float zextent = zmax - zmin;
  531. pmesh = merged->meshes;
  532. for (int i = 0; i < merged->nmeshes; i++, pmesh++) {
  533. float* pzed = (*pmesh)->points + 2;
  534. float zed = zmin + zextent * i / (merged->nmeshes - 1);
  535. for (int j = 0; j < (*pmesh)->npoints; j++, pzed += 3) {
  536. *pzed = zed;
  537. }
  538. }
  539. if (!(snap & PAR_MSQUARES_CONNECT)) {
  540. return merged;
  541. }
  542. for (int i = 1; i < merged->nmeshes; i++) {
  543. par_msquares__mesh* mesh = merged->meshes[i];
  544. // Find all extrusion points. This is tightly coupled to the
  545. // tessellation code, which generates two "connector" triangles for each
  546. // extruded edge. The first two verts of the second triangle are the
  547. // verts that need to be displaced.
  548. char* markers = PAR_CALLOC(char, mesh->npoints);
  549. int tri = mesh->ntriangles - mesh->nconntriangles;
  550. while (tri < mesh->ntriangles) {
  551. markers[mesh->triangles[tri * 3 + 3]] = 1;
  552. markers[mesh->triangles[tri * 3 + 4]] = 1;
  553. tri += 2;
  554. }
  555. // Displace all extrusion points down to the previous level.
  556. float zed = zmin + zextent * (i - 1) / (merged->nmeshes - 1);
  557. float* pzed = mesh->points + 2;
  558. for (int j = 0; j < mesh->npoints; j++, pzed += 3) {
  559. if (markers[j]) {
  560. *pzed = zed;
  561. }
  562. }
  563. free(markers);
  564. }
  565. return merged;
  566. }
  567. static void par_remove_unreferenced_verts(par_msquares__mesh* mesh)
  568. {
  569. if (mesh->npoints == 0) {
  570. return;
  571. }
  572. char* markers = PAR_CALLOC(char, mesh->npoints);
  573. PAR_MSQUARES_T const* ptris = mesh->triangles;
  574. int newnpts = 0;
  575. for (int i = 0; i < mesh->ntriangles * 3; i++, ptris++) {
  576. if (!markers[*ptris]) {
  577. newnpts++;
  578. markers[*ptris] = 1;
  579. }
  580. }
  581. float* newpts = PAR_CALLOC(float, newnpts * mesh->dim);
  582. PAR_MSQUARES_T* mapping = PAR_CALLOC(PAR_MSQUARES_T, mesh->npoints);
  583. float const* ppts = mesh->points;
  584. float* pnewpts = newpts;
  585. int j = 0;
  586. if (mesh->dim == 3) {
  587. for (int i = 0; i < mesh->npoints; i++, ppts += 3) {
  588. if (markers[i]) {
  589. *pnewpts++ = ppts[0];
  590. *pnewpts++ = ppts[1];
  591. *pnewpts++ = ppts[2];
  592. mapping[i] = j++;
  593. }
  594. }
  595. } else {
  596. for (int i = 0; i < mesh->npoints; i++, ppts += 2) {
  597. if (markers[i]) {
  598. *pnewpts++ = ppts[0];
  599. *pnewpts++ = ppts[1];
  600. mapping[i] = j++;
  601. }
  602. }
  603. }
  604. free(mesh->points);
  605. free(markers);
  606. mesh->points = newpts;
  607. mesh->npoints = newnpts;
  608. for (int i = 0; i < mesh->ntriangles * 3; i++) {
  609. mesh->triangles[i] = mapping[mesh->triangles[i]];
  610. }
  611. free(mapping);
  612. }
  613. par_msquares_meshlist* par_msquares_function(int width, int height,
  614. int cellsize, int flags, void* context, par_msquares_inside_fn insidefn,
  615. par_msquares_height_fn heightfn)
  616. {
  617. assert(width > 0 && width % cellsize == 0);
  618. assert(height > 0 && height % cellsize == 0);
  619. if (flags & PAR_MSQUARES_DUAL) {
  620. int connect = flags & PAR_MSQUARES_CONNECT;
  621. int snap = flags & PAR_MSQUARES_SNAP;
  622. int heights = flags & PAR_MSQUARES_HEIGHTS;
  623. if (!heights) {
  624. snap = connect = 0;
  625. }
  626. flags ^= PAR_MSQUARES_INVERT;
  627. flags &= ~PAR_MSQUARES_DUAL;
  628. flags &= ~PAR_MSQUARES_CONNECT;
  629. par_msquares_meshlist* m[2];
  630. m[0] = par_msquares_function(width, height, cellsize, flags,
  631. context, insidefn, heightfn);
  632. flags ^= PAR_MSQUARES_INVERT;
  633. if (connect) {
  634. flags |= PAR_MSQUARES_CONNECT;
  635. }
  636. m[1] = par_msquares_function(width, height, cellsize, flags,
  637. context, insidefn, heightfn);
  638. return par_msquares__merge(m, 2, snap | connect);
  639. }
  640. int invert = flags & PAR_MSQUARES_INVERT;
  641. // Create the two code tables if we haven't already. These are tables of
  642. // fixed constants, so it's embarassing that we use dynamic memory
  643. // allocation for them. However it's easy and it's one-time-only.
  644. if (!par_msquares_binary_point_table) {
  645. par_init_tables();
  646. }
  647. // Allocate the meshlist and the first mesh.
  648. par_msquares_meshlist* mlist = PAR_CALLOC(par_msquares_meshlist, 1);
  649. mlist->nmeshes = 1;
  650. mlist->meshes = PAR_CALLOC(par_msquares__mesh*, 1);
  651. mlist->meshes[0] = PAR_CALLOC(par_msquares__mesh, 1);
  652. par_msquares__mesh* mesh = mlist->meshes[0];
  653. mesh->dim = (flags & PAR_MSQUARES_HEIGHTS) ? 3 : 2;
  654. int ncols = width / cellsize;
  655. int nrows = height / cellsize;
  656. // Worst case is four triangles and six verts per cell, so allocate that
  657. // much.
  658. int maxtris = ncols * nrows * 4;
  659. int maxpts = ncols * nrows * 6;
  660. int maxedges = ncols * nrows * 2;
  661. // However, if we include extrusion triangles for boundary edges,
  662. // we need space for another 4 triangles and 4 points per cell.
  663. PAR_MSQUARES_T* conntris = 0;
  664. int nconntris = 0;
  665. PAR_MSQUARES_T* edgemap = 0;
  666. if (flags & PAR_MSQUARES_CONNECT) {
  667. conntris = PAR_CALLOC(PAR_MSQUARES_T, maxedges * 6);
  668. maxtris += maxedges * 2;
  669. maxpts += maxedges * 2;
  670. edgemap = PAR_CALLOC(PAR_MSQUARES_T, maxpts);
  671. for (int i = 0; i < maxpts; i++) {
  672. edgemap[i] = 0xffff;
  673. }
  674. }
  675. PAR_MSQUARES_T* tris = PAR_CALLOC(PAR_MSQUARES_T, maxtris * 3);
  676. int ntris = 0;
  677. float* pts = PAR_CALLOC(float, maxpts * mesh->dim);
  678. int npts = 0;
  679. // The "verts" x/y/z arrays are the 4 corners and 4 midpoints around the
  680. // square, in counter-clockwise order. The origin of "triangle space" is at
  681. // the lower-left, although we expect the image data to be in raster order
  682. // (starts at top-left).
  683. float vertsx[8], vertsy[8];
  684. float normalization = 1.0f / PAR_MAX(width, height);
  685. float normalized_cellsize = cellsize * normalization;
  686. int maxrow = (height - 1) * width;
  687. PAR_MSQUARES_T* ptris = tris;
  688. PAR_MSQUARES_T* pconntris = conntris;
  689. float* ppts = pts;
  690. uint8_t* prevrowmasks = PAR_CALLOC(uint8_t, ncols);
  691. int* prevrowinds = PAR_CALLOC(int, ncols * 3);
  692. // If simplification is enabled, we need to track all 'F' cells and their
  693. // respective triangle indices.
  694. uint8_t* simplification_codes = 0;
  695. PAR_MSQUARES_T* simplification_tris = 0;
  696. uint8_t* simplification_ntris = 0;
  697. if (flags & PAR_MSQUARES_SIMPLIFY) {
  698. simplification_codes = PAR_CALLOC(uint8_t, nrows * ncols);
  699. simplification_tris = PAR_CALLOC(PAR_MSQUARES_T, nrows * ncols);
  700. simplification_ntris = PAR_CALLOC(uint8_t, nrows * ncols);
  701. }
  702. // Do the march!
  703. for (int row = 0; row < nrows; row++) {
  704. vertsx[0] = vertsx[6] = vertsx[7] = 0;
  705. vertsx[1] = vertsx[5] = 0.5 * normalized_cellsize;
  706. vertsx[2] = vertsx[3] = vertsx[4] = normalized_cellsize;
  707. vertsy[0] = vertsy[1] = vertsy[2] = normalized_cellsize * (row + 1);
  708. vertsy[4] = vertsy[5] = vertsy[6] = normalized_cellsize * row;
  709. vertsy[3] = vertsy[7] = normalized_cellsize * (row + 0.5);
  710. int northi = row * cellsize * width;
  711. int southi = PAR_MIN(northi + cellsize * width, maxrow);
  712. int northwest = invert ^ insidefn(northi, context);
  713. int southwest = invert ^ insidefn(southi, context);
  714. int previnds[8] = {0};
  715. uint8_t prevmask = 0;
  716. for (int col = 0; col < ncols; col++) {
  717. northi += cellsize;
  718. southi += cellsize;
  719. if (col == ncols - 1) {
  720. northi--;
  721. southi--;
  722. }
  723. int northeast = invert ^ insidefn(northi, context);
  724. int southeast = invert ^ insidefn(southi, context);
  725. int code = southwest | (southeast << 1) | (northwest << 2) |
  726. (northeast << 3);
  727. int const* pointspec = par_msquares_binary_point_table[code];
  728. int ptspeclength = *pointspec++;
  729. int currinds[8] = {0};
  730. uint8_t mask = 0;
  731. uint8_t prevrowmask = prevrowmasks[col];
  732. while (ptspeclength--) {
  733. int midp = *pointspec++;
  734. int bit = 1 << midp;
  735. mask |= bit;
  736. // The following six conditionals perform welding to reduce the
  737. // number of vertices. The first three perform welding with the
  738. // cell to the west; the latter three perform welding with the
  739. // cell to the north.
  740. if (bit == 1 && (prevmask & 4)) {
  741. currinds[midp] = previnds[2];
  742. continue;
  743. }
  744. if (bit == 128 && (prevmask & 8)) {
  745. currinds[midp] = previnds[3];
  746. continue;
  747. }
  748. if (bit == 64 && (prevmask & 16)) {
  749. currinds[midp] = previnds[4];
  750. continue;
  751. }
  752. if (bit == 16 && (prevrowmask & 4)) {
  753. currinds[midp] = prevrowinds[col * 3 + 2];
  754. continue;
  755. }
  756. if (bit == 32 && (prevrowmask & 2)) {
  757. currinds[midp] = prevrowinds[col * 3 + 1];
  758. continue;
  759. }
  760. if (bit == 64 && (prevrowmask & 1)) {
  761. currinds[midp] = prevrowinds[col * 3 + 0];
  762. continue;
  763. }
  764. ppts[0] = vertsx[midp];
  765. ppts[1] = vertsy[midp];
  766. // Adjust the midpoints to a more exact crossing point.
  767. if (midp == 1) {
  768. int begin = southi - cellsize / 2;
  769. int previous = 0;
  770. for (int i = 0; i < cellsize; i++) {
  771. int offset = begin + i / 2 * ((i % 2) ? -1 : 1);
  772. int inside = insidefn(offset, context);
  773. if (i > 0 && inside != previous) {
  774. ppts[0] = normalization *
  775. (col * cellsize + offset - southi + cellsize);
  776. break;
  777. }
  778. previous = inside;
  779. }
  780. } else if (midp == 5) {
  781. int begin = northi - cellsize / 2;
  782. int previous = 0;
  783. for (int i = 0; i < cellsize; i++) {
  784. int offset = begin + i / 2 * ((i % 2) ? -1 : 1);
  785. int inside = insidefn(offset, context);
  786. if (i > 0 && inside != previous) {
  787. ppts[0] = normalization *
  788. (col * cellsize + offset - northi + cellsize);
  789. break;
  790. }
  791. previous = inside;
  792. }
  793. } else if (midp == 3) {
  794. int begin = northi + width * cellsize / 2;
  795. int previous = 0;
  796. for (int i = 0; i < cellsize; i++) {
  797. int offset = begin +
  798. width * (i / 2 * ((i % 2) ? -1 : 1));
  799. int inside = insidefn(offset, context);
  800. if (i > 0 && inside != previous) {
  801. ppts[1] = normalization *
  802. (row * cellsize +
  803. (offset - northi) / (float) width);
  804. break;
  805. }
  806. previous = inside;
  807. }
  808. } else if (midp == 7) {
  809. int begin = northi + width * cellsize / 2 - cellsize;
  810. int previous = 0;
  811. for (int i = 0; i < cellsize; i++) {
  812. int offset = begin +
  813. width * (i / 2 * ((i % 2) ? -1 : 1));
  814. int inside = insidefn(offset, context);
  815. if (i > 0 && inside != previous) {
  816. ppts[1] = normalization *
  817. (row * cellsize +
  818. (offset - northi - cellsize) / (float) width);
  819. break;
  820. }
  821. previous = inside;
  822. }
  823. }
  824. if (mesh->dim == 3) {
  825. if (width > height) {
  826. ppts[2] = heightfn(ppts[0], ppts[1] * width / height,
  827. context);
  828. } else {
  829. ppts[2] = heightfn(ppts[0] * height / width, ppts[1],
  830. context);
  831. }
  832. }
  833. ppts += mesh->dim;
  834. currinds[midp] = npts++;
  835. }
  836. int const* trianglespec = par_msquares_binary_triangle_table[code];
  837. int trispeclength = *trianglespec++;
  838. if (flags & PAR_MSQUARES_SIMPLIFY) {
  839. simplification_codes[ncols * row + col] = code;
  840. simplification_tris[ncols * row + col] = ntris;
  841. simplification_ntris[ncols * row + col] = trispeclength;
  842. }
  843. // Add triangles.
  844. while (trispeclength--) {
  845. int a = *trianglespec++;
  846. int b = *trianglespec++;
  847. int c = *trianglespec++;
  848. *ptris++ = currinds[c];
  849. *ptris++ = currinds[b];
  850. *ptris++ = currinds[a];
  851. ntris++;
  852. }
  853. // Create two extrusion triangles for each boundary edge.
  854. if (flags & PAR_MSQUARES_CONNECT) {
  855. trianglespec = par_msquares_binary_triangle_table[code];
  856. trispeclength = *trianglespec++;
  857. while (trispeclength--) {
  858. int a = *trianglespec++;
  859. int b = *trianglespec++;
  860. int c = *trianglespec++;
  861. int i = currinds[a];
  862. int j = currinds[b];
  863. int k = currinds[c];
  864. int u = 0, v = 0, w = 0;
  865. if ((a % 2) && (b % 2)) {
  866. u = v = 1;
  867. } else if ((a % 2) && (c % 2)) {
  868. u = w = 1;
  869. } else if ((b % 2) && (c % 2)) {
  870. v = w = 1;
  871. } else {
  872. continue;
  873. }
  874. if (u && edgemap[i] == 0xffff) {
  875. for (int d = 0; d < mesh->dim; d++) {
  876. *ppts++ = pts[i * mesh->dim + d];
  877. }
  878. edgemap[i] = npts++;
  879. }
  880. if (v && edgemap[j] == 0xffff) {
  881. for (int d = 0; d < mesh->dim; d++) {
  882. *ppts++ = pts[j * mesh->dim + d];
  883. }
  884. edgemap[j] = npts++;
  885. }
  886. if (w && edgemap[k] == 0xffff) {
  887. for (int d = 0; d < mesh->dim; d++) {
  888. *ppts++ = pts[k * mesh->dim + d];
  889. }
  890. edgemap[k] = npts++;
  891. }
  892. if ((a % 2) && (b % 2)) {
  893. *pconntris++ = i;
  894. *pconntris++ = j;
  895. *pconntris++ = edgemap[j];
  896. *pconntris++ = edgemap[j];
  897. *pconntris++ = edgemap[i];
  898. *pconntris++ = i;
  899. } else if ((a % 2) && (c % 2)) {
  900. *pconntris++ = edgemap[k];
  901. *pconntris++ = k;
  902. *pconntris++ = i;
  903. *pconntris++ = edgemap[i];
  904. *pconntris++ = edgemap[k];
  905. *pconntris++ = i;
  906. } else if ((b % 2) && (c % 2)) {
  907. *pconntris++ = j;
  908. *pconntris++ = k;
  909. *pconntris++ = edgemap[k];
  910. *pconntris++ = edgemap[k];
  911. *pconntris++ = edgemap[j];
  912. *pconntris++ = j;
  913. }
  914. nconntris += 2;
  915. }
  916. }
  917. // Prepare for the next cell.
  918. prevrowmasks[col] = mask;
  919. prevrowinds[col * 3 + 0] = currinds[0];
  920. prevrowinds[col * 3 + 1] = currinds[1];
  921. prevrowinds[col * 3 + 2] = currinds[2];
  922. prevmask = mask;
  923. northwest = northeast;
  924. southwest = southeast;
  925. for (int i = 0; i < 8; i++) {
  926. previnds[i] = currinds[i];
  927. vertsx[i] += normalized_cellsize;
  928. }
  929. }
  930. }
  931. free(edgemap);
  932. free(prevrowmasks);
  933. free(prevrowinds);
  934. // Perform quick-n-dirty simplification by iterating two rows at a time.
  935. // In no way does this create the simplest possible mesh, but at least it's
  936. // fast and easy.
  937. if (flags & PAR_MSQUARES_SIMPLIFY) {
  938. int in_run = 0, start_run;
  939. // First figure out how many triangles we can eliminate.
  940. int neliminated_triangles = 0;
  941. for (int row = 0; row < nrows - 1; row += 2) {
  942. for (int col = 0; col < ncols; col++) {
  943. int a = simplification_codes[ncols * row + col] == 0xf;
  944. int b = simplification_codes[ncols * row + col + ncols] == 0xf;
  945. if (a && b) {
  946. if (!in_run) {
  947. in_run = 1;
  948. start_run = col;
  949. }
  950. continue;
  951. }
  952. if (in_run) {
  953. in_run = 0;
  954. int run_width = col - start_run;
  955. neliminated_triangles += run_width * 4 - 2;
  956. }
  957. }
  958. if (in_run) {
  959. in_run = 0;
  960. int run_width = ncols - start_run;
  961. neliminated_triangles += run_width * 4 - 2;
  962. }
  963. }
  964. // Build a new index array cell-by-cell. If any given cell is 'F' and
  965. // its neighbor to the south is also 'F', then it's part of a run.
  966. int nnewtris = ntris + nconntris - neliminated_triangles;
  967. PAR_MSQUARES_T* newtris = PAR_CALLOC(PAR_MSQUARES_T, nnewtris * 3);
  968. PAR_MSQUARES_T* pnewtris = newtris;
  969. in_run = 0;
  970. for (int row = 0; row < nrows - 1; row += 2) {
  971. for (int col = 0; col < ncols; col++) {
  972. int cell = ncols * row + col;
  973. int south = cell + ncols;
  974. int a = simplification_codes[cell] == 0xf;
  975. int b = simplification_codes[south] == 0xf;
  976. if (a && b) {
  977. if (!in_run) {
  978. in_run = 1;
  979. start_run = col;
  980. }
  981. continue;
  982. }
  983. if (in_run) {
  984. in_run = 0;
  985. int nw_cell = ncols * row + start_run;
  986. int ne_cell = ncols * row + col - 1;
  987. int sw_cell = nw_cell + ncols;
  988. int se_cell = ne_cell + ncols;
  989. int nw_tri = simplification_tris[nw_cell];
  990. int ne_tri = simplification_tris[ne_cell];
  991. int sw_tri = simplification_tris[sw_cell];
  992. int se_tri = simplification_tris[se_cell];
  993. int nw_corner = nw_tri * 3 + 4;
  994. int ne_corner = ne_tri * 3 + 0;
  995. int sw_corner = sw_tri * 3 + 2;
  996. int se_corner = se_tri * 3 + 1;
  997. *pnewtris++ = tris[se_corner];
  998. *pnewtris++ = tris[sw_corner];
  999. *pnewtris++ = tris[nw_corner];
  1000. *pnewtris++ = tris[nw_corner];
  1001. *pnewtris++ = tris[ne_corner];
  1002. *pnewtris++ = tris[se_corner];
  1003. }
  1004. int ncelltris = simplification_ntris[cell];
  1005. int celltri = simplification_tris[cell];
  1006. for (int t = 0; t < ncelltris; t++, celltri++) {
  1007. *pnewtris++ = tris[celltri * 3];
  1008. *pnewtris++ = tris[celltri * 3 + 1];
  1009. *pnewtris++ = tris[celltri * 3 + 2];
  1010. }
  1011. ncelltris = simplification_ntris[south];
  1012. celltri = simplification_tris[south];
  1013. for (int t = 0; t < ncelltris; t++, celltri++) {
  1014. *pnewtris++ = tris[celltri * 3];
  1015. *pnewtris++ = tris[celltri * 3 + 1];
  1016. *pnewtris++ = tris[celltri * 3 + 2];
  1017. }
  1018. }
  1019. if (in_run) {
  1020. in_run = 0;
  1021. int nw_cell = ncols * row + start_run;
  1022. int ne_cell = ncols * row + ncols - 1;
  1023. int sw_cell = nw_cell + ncols;
  1024. int se_cell = ne_cell + ncols;
  1025. int nw_tri = simplification_tris[nw_cell];
  1026. int ne_tri = simplification_tris[ne_cell];
  1027. int sw_tri = simplification_tris[sw_cell];
  1028. int se_tri = simplification_tris[se_cell];
  1029. int nw_corner = nw_tri * 3 + 4;
  1030. int ne_corner = ne_tri * 3 + 0;
  1031. int sw_corner = sw_tri * 3 + 2;
  1032. int se_corner = se_tri * 3 + 1;
  1033. *pnewtris++ = tris[se_corner];
  1034. *pnewtris++ = tris[sw_corner];
  1035. *pnewtris++ = tris[nw_corner];
  1036. *pnewtris++ = tris[nw_corner];
  1037. *pnewtris++ = tris[ne_corner];
  1038. *pnewtris++ = tris[se_corner];
  1039. }
  1040. }
  1041. ptris = pnewtris;
  1042. ntris -= neliminated_triangles;
  1043. free(tris);
  1044. tris = newtris;
  1045. free(simplification_codes);
  1046. free(simplification_tris);
  1047. free(simplification_ntris);
  1048. // Remove unreferenced points.
  1049. char* markers = PAR_CALLOC(char, npts);
  1050. ptris = tris;
  1051. int newnpts = 0;
  1052. for (int i = 0; i < ntris * 3; i++, ptris++) {
  1053. if (!markers[*ptris]) {
  1054. newnpts++;
  1055. markers[*ptris] = 1;
  1056. }
  1057. }
  1058. for (int i = 0; i < nconntris * 3; i++) {
  1059. if (!markers[conntris[i]]) {
  1060. newnpts++;
  1061. markers[conntris[i]] = 1;
  1062. }
  1063. }
  1064. float* newpts = PAR_CALLOC(float, newnpts * mesh->dim);
  1065. PAR_MSQUARES_T* mapping = PAR_CALLOC(PAR_MSQUARES_T, npts);
  1066. ppts = pts;
  1067. float* pnewpts = newpts;
  1068. int j = 0;
  1069. if (mesh->dim == 3) {
  1070. for (int i = 0; i < npts; i++, ppts += 3) {
  1071. if (markers[i]) {
  1072. *pnewpts++ = ppts[0];
  1073. *pnewpts++ = ppts[1];
  1074. *pnewpts++ = ppts[2];
  1075. mapping[i] = j++;
  1076. }
  1077. }
  1078. } else {
  1079. for (int i = 0; i < npts; i++, ppts += 2) {
  1080. if (markers[i]) {
  1081. *pnewpts++ = ppts[0];
  1082. *pnewpts++ = ppts[1];
  1083. mapping[i] = j++;
  1084. }
  1085. }
  1086. }
  1087. free(pts);
  1088. free(markers);
  1089. pts = newpts;
  1090. npts = newnpts;
  1091. for (int i = 0; i < ntris * 3; i++) {
  1092. tris[i] = mapping[tris[i]];
  1093. }
  1094. for (int i = 0; i < nconntris * 3; i++) {
  1095. conntris[i] = mapping[conntris[i]];
  1096. }
  1097. free(mapping);
  1098. }
  1099. // Append all extrusion triangles to the main triangle array.
  1100. // We need them to be last so that they form a contiguous sequence.
  1101. pconntris = conntris;
  1102. for (int i = 0; i < nconntris; i++) {
  1103. *ptris++ = *pconntris++;
  1104. *ptris++ = *pconntris++;
  1105. *ptris++ = *pconntris++;
  1106. ntris++;
  1107. }
  1108. free(conntris);
  1109. // Final cleanup and return.
  1110. assert(npts <= maxpts);
  1111. assert(ntris <= maxtris);
  1112. mesh->npoints = npts;
  1113. mesh->points = pts;
  1114. mesh->ntriangles = ntris;
  1115. mesh->triangles = tris;
  1116. mesh->nconntriangles = nconntris;
  1117. return mlist;
  1118. }
  1119. typedef struct {
  1120. PAR_MSQUARES_T outera;
  1121. PAR_MSQUARES_T outerb;
  1122. PAR_MSQUARES_T innera;
  1123. PAR_MSQUARES_T innerb;
  1124. char i;
  1125. char j;
  1126. par_msquares__mesh* mesh;
  1127. int mesh_index;
  1128. } par_connector;
  1129. static par_connector* par_conn_find(par_connector* conns, int nconns,
  1130. char i, char j)
  1131. {
  1132. for (int c = 0; c < nconns; c++) {
  1133. if (conns[c].i == i && conns[c].j == j) {
  1134. return conns + c;
  1135. }
  1136. }
  1137. return 0;
  1138. }
  1139. static int par_msquares_cmp(const void *a, const void *b)
  1140. {
  1141. uint32_t arg1 = *((uint32_t const*) a);
  1142. uint32_t arg2 = *((uint32_t const*) b);
  1143. if (arg1 < arg2) return -1;
  1144. if (arg1 > arg2) return 1;
  1145. return 0;
  1146. }
  1147. typedef int (*par_msquares_code_fn)(int, int, int, int, void*);
  1148. static int par_msquares_multi_code(int sw, int se, int ne, int nw)
  1149. {
  1150. int code[4];
  1151. int ncols = 0;
  1152. code[0] = ncols++;
  1153. if (se == sw) {
  1154. code[1] = code[0];
  1155. } else {
  1156. code[1] = ncols++;
  1157. }
  1158. if (ne == se) {
  1159. code[2] = code[1];
  1160. } else if (ne == sw) {
  1161. code[2] = code[0];
  1162. } else {
  1163. code[2] = ncols++;
  1164. }
  1165. if (nw == ne) {
  1166. code[3] = code[2];
  1167. } else if (nw == se) {
  1168. code[3] = code[1];
  1169. } else if (nw == sw) {
  1170. code[3] = code[0];
  1171. } else {
  1172. code[3] = ncols++;
  1173. }
  1174. return code[0] | (code[1] << 2) | (code[2] << 4) | (code[3] << 6);
  1175. }
  1176. static uint32_t par_msquares_argb(par_byte const* pdata, int bpp)
  1177. {
  1178. uint32_t color = 0;
  1179. if (bpp == 4) {
  1180. color |= pdata[2];
  1181. color |= pdata[1] << 8;
  1182. color |= pdata[0] << 16;
  1183. color |= pdata[3] << 24;
  1184. return color;
  1185. }
  1186. for (int j = 0; j < bpp; j++) {
  1187. color <<= 8;
  1188. color |= pdata[j];
  1189. }
  1190. return color;
  1191. }
  1192. // Merge connective triangles into the primary triangle list.
  1193. static void par_msquares__finalize(par_msquares_meshlist* mlist)
  1194. {
  1195. if (mlist->nmeshes < 2 || mlist->meshes[1]->nconntriangles == 0) {
  1196. return;
  1197. }
  1198. for (int m = 1; m < mlist->nmeshes; m++) {
  1199. par_msquares__mesh* mesh = mlist->meshes[m];
  1200. int ntris = mesh->ntriangles + mesh->nconntriangles;
  1201. PAR_MSQUARES_T* triangles = PAR_CALLOC(PAR_MSQUARES_T, ntris * 3);
  1202. PAR_MSQUARES_T* dst = triangles;
  1203. PAR_MSQUARES_T const* src = mesh->triangles;
  1204. for (int t = 0; t < mesh->ntriangles; t++) {
  1205. *dst++ = *src++;
  1206. *dst++ = *src++;
  1207. *dst++ = *src++;
  1208. }
  1209. src = mesh->conntri;
  1210. for (int t = 0; t < mesh->nconntriangles; t++) {
  1211. *dst++ = *src++;
  1212. *dst++ = *src++;
  1213. *dst++ = *src++;
  1214. }
  1215. free(mesh->triangles);
  1216. free(mesh->conntri);
  1217. mesh->triangles = triangles;
  1218. mesh->ntriangles = ntris;
  1219. mesh->conntri = 0;
  1220. mesh->nconntriangles = 0;
  1221. }
  1222. }
  1223. static par__uint16list* par__uint16list_create()
  1224. {
  1225. par__uint16list* list = PAR_CALLOC(par__uint16list, 1);
  1226. list->count = 0;
  1227. list->capacity = 32;
  1228. list->values = PAR_CALLOC(PAR_MSQUARES_T, list->capacity);
  1229. return list;
  1230. }
  1231. static void par__uint16list_add3(par__uint16list* list,
  1232. PAR_MSQUARES_T a, PAR_MSQUARES_T b, PAR_MSQUARES_T c)
  1233. {
  1234. if (list->count + 3 > list->capacity) {
  1235. list->capacity *= 2;
  1236. list->values = PAR_REALLOC(PAR_MSQUARES_T, list->values, list->capacity);
  1237. }
  1238. list->values[list->count++] = a;
  1239. list->values[list->count++] = b;
  1240. list->values[list->count++] = c;
  1241. }
  1242. static void par__uint16list_free(par__uint16list* list)
  1243. {
  1244. if (list) {
  1245. PAR_FREE(list->values);
  1246. PAR_FREE(list);
  1247. }
  1248. }
  1249. static void par_msquares__repair_tjunctions(par_msquares_meshlist* mlist)
  1250. {
  1251. for (int m = 0; m < mlist->nmeshes; m++) {
  1252. par_msquares__mesh* mesh = mlist->meshes[m];
  1253. par__uint16list* tjunctions = mesh->tjunctions;
  1254. int njunctions = (int) tjunctions->count / 3;
  1255. if (njunctions == 0) {
  1256. continue;
  1257. }
  1258. int ntriangles = mesh->ntriangles + njunctions;
  1259. mesh->triangles = PAR_REALLOC(PAR_MSQUARES_T, mesh->triangles,
  1260. ntriangles * 3);
  1261. PAR_MSQUARES_T const* jun = tjunctions->values;
  1262. PAR_MSQUARES_T* new_triangles = mesh->triangles + mesh->ntriangles * 3;
  1263. int ncreated = 0;
  1264. for (int j = 0; j < njunctions; j++, jun += 3) {
  1265. PAR_MSQUARES_T* tri = mesh->triangles;
  1266. int t;
  1267. for (t = 0; t < mesh->ntriangles; t++, tri += 3) {
  1268. int i = -1;
  1269. if (tri[0] == jun[0] && tri[1] == jun[1]) {
  1270. i = 0;
  1271. } else if (tri[1] == jun[0] && tri[2] == jun[1]) {
  1272. i = 1;
  1273. } else if (tri[2] == jun[0] && tri[0] == jun[1]) {
  1274. i = 2;
  1275. } else {
  1276. continue;
  1277. }
  1278. new_triangles[0] = tri[(i + 0) % 3];
  1279. new_triangles[1] = jun[2];
  1280. new_triangles[2] = tri[(i + 2) % 3];
  1281. tri[(i + 0) % 3] = jun[2];
  1282. new_triangles += 3;
  1283. ncreated++;
  1284. break;
  1285. }
  1286. // TODO: Need to investigate the "msquares_multi_diagram.obj" test.
  1287. assert(t != mesh->ntriangles &&
  1288. "Error with T-Junction repair; please disable the CLEAN flag.");
  1289. }
  1290. mesh->ntriangles += ncreated;
  1291. }
  1292. }
  1293. par_msquares_meshlist* par_msquares_color_multi(par_byte const* data, int width,
  1294. int height, int cellsize, int bpp, int flags)
  1295. {
  1296. if (!par_msquares_binary_point_table) {
  1297. par_init_tables();
  1298. }
  1299. const int ncols = width / cellsize;
  1300. const int nrows = height / cellsize;
  1301. const int maxrow = (height - 1) * width;
  1302. const int ncells = ncols * nrows;
  1303. const int dim = (flags & PAR_MSQUARES_HEIGHTS) ? 3 : 2;
  1304. const int west_to_east[9] = { 2, -1, -1, -1, -1, -1, 4, 3, -1 };
  1305. const int north_to_south[9] = { -1, -1, -1, -1, 2, 1, 0, -1, -1 };
  1306. assert(!(flags & PAR_MSQUARES_HEIGHTS) || bpp == 4);
  1307. assert(bpp > 0 && bpp <= 4 && "Bytes per pixel must be 1, 2, 3, or 4.");
  1308. assert(!(flags & PAR_MSQUARES_CLEAN) || !(flags & PAR_MSQUARES_SIMPLIFY));
  1309. assert(!(flags & PAR_MSQUARES_SNAP) &&
  1310. "SNAP is not supported with color_multi");
  1311. assert(!(flags & PAR_MSQUARES_INVERT) &&
  1312. "INVERT is not supported with color_multi");
  1313. assert(!(flags & PAR_MSQUARES_DUAL) &&
  1314. "DUAL is not supported with color_multi");
  1315. // Find all unique colors and ensure there are no more than 256 colors.
  1316. uint32_t colors[256];
  1317. int ncolors = 0;
  1318. par_byte const* pdata = data;
  1319. for (int i = 0; i < width * height; i++, pdata += bpp) {
  1320. uint32_t color = par_msquares_argb(pdata, bpp);
  1321. if (0 == bsearch(&color, colors, ncolors, 4, par_msquares_cmp)) {
  1322. assert(ncolors < 256);
  1323. colors[ncolors++] = color;
  1324. qsort(colors, ncolors, sizeof(uint32_t), par_msquares_cmp);
  1325. }
  1326. }
  1327. // Convert the color image to grayscale using the mapping table.
  1328. par_byte* pixels = PAR_CALLOC(par_byte, width * height);
  1329. pdata = data;
  1330. for (int i = 0; i < width * height; i++, pdata += bpp) {
  1331. uint32_t color = par_msquares_argb(pdata, bpp);
  1332. void* result = bsearch(&color, colors, ncolors, 4, par_msquares_cmp);
  1333. pixels[i] = (uint32_t*) result - &colors[0];
  1334. }
  1335. // Allocate 1 mesh for each color.
  1336. par_msquares_meshlist* mlist = PAR_CALLOC(par_msquares_meshlist, 1);
  1337. mlist->nmeshes = ncolors;
  1338. mlist->meshes = PAR_CALLOC(par_msquares__mesh*, ncolors);
  1339. par_msquares__mesh* mesh;
  1340. int maxtris_per_cell = 6;
  1341. int maxpts_per_cell = 9;
  1342. if (flags & PAR_MSQUARES_CONNECT) {
  1343. maxpts_per_cell += 6;
  1344. }
  1345. for (int i = 0; i < ncolors; i++) {
  1346. mesh = mlist->meshes[i] = PAR_CALLOC(par_msquares__mesh, 1);
  1347. mesh->color = colors[i];
  1348. mesh->points = PAR_CALLOC(float, ncells * maxpts_per_cell * dim);
  1349. mesh->triangles = PAR_CALLOC(PAR_MSQUARES_T, ncells * maxtris_per_cell * 3);
  1350. mesh->dim = dim;
  1351. mesh->tjunctions = par__uint16list_create();
  1352. if (flags & PAR_MSQUARES_CONNECT) {
  1353. mesh->conntri = PAR_CALLOC(PAR_MSQUARES_T, ncells * 8 * 3);
  1354. }
  1355. }
  1356. // The "verts" x/y/z arrays are the 4 corners and 4 midpoints around the
  1357. // square, in counter-clockwise order, starting at the lower-left. The
  1358. // ninth vert is the center point.
  1359. float vertsx[9], vertsy[9];
  1360. float normalization = 1.0f / PAR_MAX(width, height);
  1361. float normalized_cellsize = cellsize * normalization;
  1362. uint8_t cella[256];
  1363. uint8_t cellb[256];
  1364. uint8_t* currcell = cella;
  1365. uint8_t* prevcell = cellb;
  1366. PAR_MSQUARES_T inds0[256 * 9];
  1367. PAR_MSQUARES_T inds1[256 * 9];
  1368. PAR_MSQUARES_T* currinds = inds0;
  1369. PAR_MSQUARES_T* previnds = inds1;
  1370. PAR_MSQUARES_T* rowindsa = PAR_CALLOC(PAR_MSQUARES_T, ncols * 3 * 256);
  1371. uint8_t* rowcellsa = PAR_CALLOC(uint8_t, ncols * 256);
  1372. PAR_MSQUARES_T* rowindsb = PAR_CALLOC(PAR_MSQUARES_T, ncols * 3 * 256);
  1373. uint8_t* rowcellsb = PAR_CALLOC(uint8_t, ncols * 256);
  1374. PAR_MSQUARES_T* prevrowinds = rowindsa;
  1375. PAR_MSQUARES_T* currrowinds = rowindsb;
  1376. uint8_t* prevrowcells = rowcellsa;
  1377. uint8_t* currrowcells = rowcellsb;
  1378. uint32_t* simplification_words = 0;
  1379. if (flags & PAR_MSQUARES_SIMPLIFY) {
  1380. simplification_words = PAR_CALLOC(uint32_t, 2 * nrows * ncols);
  1381. }
  1382. // Do the march!
  1383. for (int row = 0; row < nrows; row++) {
  1384. vertsx[0] = vertsx[6] = vertsx[7] = 0;
  1385. vertsx[1] = vertsx[5] = vertsx[8] = 0.5 * normalized_cellsize;
  1386. vertsx[2] = vertsx[3] = vertsx[4] = normalized_cellsize;
  1387. vertsy[0] = vertsy[1] = vertsy[2] = normalized_cellsize * (row + 1);
  1388. vertsy[4] = vertsy[5] = vertsy[6] = normalized_cellsize * row;
  1389. vertsy[3] = vertsy[7] = vertsy[8] = normalized_cellsize * (row + 0.5);
  1390. int northi = row * cellsize * width;
  1391. int southi = PAR_MIN(northi + cellsize * width, maxrow);
  1392. int nwval = pixels[northi];
  1393. int swval = pixels[southi];
  1394. memset(currrowcells, 0, ncols * 256);
  1395. for (int col = 0; col < ncols; col++) {
  1396. northi += cellsize;
  1397. southi += cellsize;
  1398. if (col == ncols - 1) {
  1399. northi--;
  1400. southi--;
  1401. }
  1402. // Obtain 8-bit code and grab the four corresponding triangle lists.
  1403. int neval = pixels[northi];
  1404. int seval = pixels[southi];
  1405. int code = par_msquares_multi_code(swval, seval, neval, nwval) >> 2;
  1406. int const* trispecs[4] = {
  1407. par_msquares_quaternary_triangle_table[code][0],
  1408. par_msquares_quaternary_triangle_table[code][1],
  1409. par_msquares_quaternary_triangle_table[code][2],
  1410. par_msquares_quaternary_triangle_table[code][3]
  1411. };
  1412. int ntris[4] = {
  1413. *trispecs[0]++,
  1414. *trispecs[1]++,
  1415. *trispecs[2]++,
  1416. *trispecs[3]++
  1417. };
  1418. int const* edgespecs[4] = {
  1419. par_msquares_quaternary_boundary_table[code][0],
  1420. par_msquares_quaternary_boundary_table[code][1],
  1421. par_msquares_quaternary_boundary_table[code][2],
  1422. par_msquares_quaternary_boundary_table[code][3]
  1423. };
  1424. int nedges[4] = {
  1425. *edgespecs[0]++,
  1426. *edgespecs[1]++,
  1427. *edgespecs[2]++,
  1428. *edgespecs[3]++
  1429. };
  1430. int vals[4] = { swval, seval, neval, nwval };
  1431. // Gather topology information.
  1432. par_connector edges[16];
  1433. int ncedges = 0;
  1434. for (int c = 0; c < 4; c++) {
  1435. int color = vals[c];
  1436. par_msquares__mesh* mesh = mlist->meshes[color];
  1437. par_connector edge;
  1438. for (int e = 0; e < nedges[c]; e++) {
  1439. char previndex = edgespecs[c][e * 2];
  1440. char currindex = edgespecs[c][e * 2 + 1];
  1441. edge.i = previndex;
  1442. edge.j = currindex;
  1443. edge.mesh_index = color;
  1444. edge.mesh = mesh;
  1445. edges[ncedges++] = edge;
  1446. }
  1447. }
  1448. assert(ncedges < 16);
  1449. // Push triangles and points into the four affected meshes.
  1450. for (int m = 0; m < ncolors; m++) {
  1451. currcell[m] = 0;
  1452. }
  1453. uint32_t colors = 0;
  1454. uint32_t counts = 0;
  1455. PAR_MSQUARES_T* conntris_start[4];
  1456. for (int c = 0; c < 4; c++) {
  1457. int color = vals[c];
  1458. colors |= color << (8 * c);
  1459. counts |= ntris[c] << (8 * c);
  1460. par_msquares__mesh* mesh = mlist->meshes[color];
  1461. float height = (mesh->color >> 24) / 255.0;
  1462. conntris_start[c] = mesh->conntri + mesh->nconntriangles * 3;
  1463. int usedpts[9] = {0};
  1464. PAR_MSQUARES_T* pcurrinds = currinds + 9 * color;
  1465. PAR_MSQUARES_T const* pprevinds = previnds + 9 * color;
  1466. PAR_MSQUARES_T const* pprevrowinds =
  1467. prevrowinds + ncols * 3 * color + col * 3;
  1468. uint8_t prevrowcell = prevrowcells[color * ncols + col];
  1469. float* pdst = mesh->points + mesh->npoints * mesh->dim;
  1470. int previndex, prevflag;
  1471. for (int t = 0; t < ntris[c] * 3; t++) {
  1472. PAR_MSQUARES_T index = trispecs[c][t];
  1473. if (usedpts[index]) {
  1474. continue;
  1475. }
  1476. usedpts[index] = 1;
  1477. if (index < 8) {
  1478. currcell[color] |= 1 << index;
  1479. }
  1480. // Vertical welding.
  1481. previndex = north_to_south[index];
  1482. prevflag = (previndex > -1) ? (1 << previndex) : 0;
  1483. if (row > 0 && (prevrowcell & prevflag)) {
  1484. pcurrinds[index] = pprevrowinds[previndex];
  1485. continue;
  1486. }
  1487. // Horizontal welding.
  1488. previndex = west_to_east[index];
  1489. prevflag = (previndex > -1) ? (1 << previndex) : 0;
  1490. if (col > 0 && (prevcell[color] & prevflag)) {
  1491. pcurrinds[index] = pprevinds[previndex];
  1492. continue;
  1493. }
  1494. // Insert brand new point.
  1495. float* vertex = pdst;
  1496. *pdst++ = vertsx[index];
  1497. *pdst++ = 1 - vertsy[index];
  1498. if (mesh->dim == 3) {
  1499. *pdst++ = height;
  1500. }
  1501. pcurrinds[index] = mesh->npoints++;
  1502. // If this is a midpoint, nudge it to the intersection.
  1503. if (index == 1) {
  1504. int begin = southi - cellsize;
  1505. for (int i = 1; i < cellsize + 1; i++) {
  1506. int val = pixels[begin + i];
  1507. if (val != pixels[begin]) {
  1508. vertex[0] = vertsx[0] + normalized_cellsize *
  1509. (float) i / cellsize;
  1510. break;
  1511. }
  1512. }
  1513. } else if (index == 3) {
  1514. int begin = northi;
  1515. for (int i = 1; i < cellsize + 1; i++) {
  1516. int val = pixels[begin + i * width];
  1517. if (val != pixels[begin]) {
  1518. vertex[1] = (1 - vertsy[4]) -
  1519. normalized_cellsize * (float) i / cellsize;
  1520. break;
  1521. }
  1522. }
  1523. }
  1524. }
  1525. // Look for T junctions and note them for later repairs.
  1526. uint8_t prc = prevrowcell;
  1527. if (usedpts[4] && !usedpts[5] && usedpts[6] && (prc & 2)) {
  1528. // Above cell had a middle vert, current cell straddles it.
  1529. par__uint16list_add3(mesh->tjunctions,
  1530. pcurrinds[4], pcurrinds[6], pprevrowinds[1]);
  1531. } else if ((prc & 1) && !(prc & 2) && (prc & 4) && usedpts[5]) {
  1532. // Current cell has a middle vert, above cell straddles it.
  1533. par__uint16list_add3(mesh->tjunctions,
  1534. pprevrowinds[0], pprevrowinds[2], pcurrinds[5]);
  1535. }
  1536. uint8_t pcc = col > 0 ? prevcell[color] : 0;
  1537. if (usedpts[0] && !usedpts[7] && usedpts[6] && (pcc & 8)) {
  1538. // Left cell had a middle vert, current cell straddles it.
  1539. par__uint16list_add3(mesh->tjunctions,
  1540. pcurrinds[6], pcurrinds[0], pprevinds[3]);
  1541. }
  1542. if ((pcc & 4) && !(pcc & 8) && (pcc & 16) && usedpts[7]) {
  1543. // Current cell has a middle vert, left cell straddles it.
  1544. par__uint16list_add3(mesh->tjunctions,
  1545. pprevinds[2], pprevinds[4], pcurrinds[7]);
  1546. }
  1547. // Stamp out the cell's triangle indices for this color.
  1548. PAR_MSQUARES_T* tdst = mesh->triangles + mesh->ntriangles * 3;
  1549. mesh->ntriangles += ntris[c];
  1550. for (int t = 0; t < ntris[c] * 3; t++) {
  1551. PAR_MSQUARES_T index = trispecs[c][t];
  1552. *tdst++ = pcurrinds[index];
  1553. }
  1554. // Add extrusion points and connective triangles if requested.
  1555. if (!(flags & PAR_MSQUARES_CONNECT)) {
  1556. continue;
  1557. }
  1558. for (int e = 0; e < nedges[c]; e++) {
  1559. int previndex = edgespecs[c][e * 2];
  1560. int currindex = edgespecs[c][e * 2 + 1];
  1561. par_connector* thisedge = par_conn_find(edges,
  1562. ncedges, previndex, currindex);
  1563. thisedge->innera = pcurrinds[previndex];
  1564. thisedge->innerb = pcurrinds[currindex];
  1565. thisedge->outera = mesh->npoints;
  1566. thisedge->outerb = mesh->npoints + 1;
  1567. par_connector* oppedge = par_conn_find(edges,
  1568. ncedges, currindex, previndex);
  1569. if (oppedge->mesh_index > color) continue;
  1570. *pdst++ = vertsx[previndex];
  1571. *pdst++ = 1 - vertsy[previndex];
  1572. if (mesh->dim == 3) {
  1573. *pdst++ = height;
  1574. }
  1575. mesh->npoints++;
  1576. *pdst++ = vertsx[currindex];
  1577. *pdst++ = 1 - vertsy[currindex];
  1578. if (mesh->dim == 3) {
  1579. *pdst++ = height;
  1580. }
  1581. mesh->npoints++;
  1582. PAR_MSQUARES_T i0 = mesh->npoints - 1;
  1583. PAR_MSQUARES_T i1 = mesh->npoints - 2;
  1584. PAR_MSQUARES_T i2 = pcurrinds[previndex];
  1585. PAR_MSQUARES_T i3 = pcurrinds[currindex];
  1586. PAR_MSQUARES_T* ptr = mesh->conntri +
  1587. mesh->nconntriangles * 3;
  1588. *ptr++ = i2; *ptr++ = i1; *ptr++ = i0;
  1589. *ptr++ = i0; *ptr++ = i3; *ptr++ = i2;
  1590. mesh->nconntriangles += 2;
  1591. }
  1592. }
  1593. // Adjust the positions of the extrusion verts.
  1594. if (flags & PAR_MSQUARES_CONNECT) {
  1595. for (int c = 0; c < 4; c++) {
  1596. int color = vals[c];
  1597. PAR_MSQUARES_T* pconninds = conntris_start[c];
  1598. par_msquares__mesh* mesh = mlist->meshes[color];
  1599. for (int e = 0; e < nedges[c]; e++) {
  1600. int previndex = edgespecs[c][e * 2];
  1601. int currindex = edgespecs[c][e * 2 + 1];
  1602. PAR_MSQUARES_T i1 = pconninds[1];
  1603. PAR_MSQUARES_T i0 = pconninds[2];
  1604. par_connector const* oppedge = par_conn_find(edges,
  1605. ncedges, currindex, previndex);
  1606. if (oppedge->mesh_index > color) continue;
  1607. int d = mesh->dim;
  1608. float* dst = mesh->points;
  1609. float const* src = oppedge->mesh->points;
  1610. dst[i0 * d + 0] = src[oppedge->innera * d + 0];
  1611. dst[i0 * d + 1] = src[oppedge->innera * d + 1];
  1612. dst[i1 * d + 0] = src[oppedge->innerb * d + 0];
  1613. dst[i1 * d + 1] = src[oppedge->innerb * d + 1];
  1614. if (d == 3) {
  1615. dst[i0 * d + 2] = src[oppedge->innera * d + 2];
  1616. dst[i1 * d + 2] = src[oppedge->innerb * d + 2];
  1617. }
  1618. pconninds += 6;
  1619. }
  1620. }
  1621. }
  1622. // Stash the bottom indices for each mesh in this cell to enable
  1623. // vertical as-you-go welding.
  1624. uint8_t* pcurrrowcells = currrowcells;
  1625. PAR_MSQUARES_T* pcurrrowinds = currrowinds;
  1626. PAR_MSQUARES_T const* pcurrinds = currinds;
  1627. for (int color = 0; color < ncolors; color++) {
  1628. pcurrrowcells[col] = currcell[color];
  1629. pcurrrowcells += ncols;
  1630. pcurrrowinds[col * 3 + 0] = pcurrinds[0];
  1631. pcurrrowinds[col * 3 + 1] = pcurrinds[1];
  1632. pcurrrowinds[col * 3 + 2] = pcurrinds[2];
  1633. pcurrrowinds += ncols * 3;
  1634. pcurrinds += 9;
  1635. }
  1636. // Stash some information later used by simplification.
  1637. if (flags & PAR_MSQUARES_SIMPLIFY) {
  1638. int cell = col + row * ncols;
  1639. simplification_words[cell * 2] = colors;
  1640. simplification_words[cell * 2 + 1] = counts;
  1641. }
  1642. // Advance the cursor.
  1643. nwval = neval;
  1644. swval = seval;
  1645. for (int i = 0; i < 9; i++) {
  1646. vertsx[i] += normalized_cellsize;
  1647. }
  1648. PAR_SWAP(uint8_t*, prevcell, currcell);
  1649. PAR_SWAP(PAR_MSQUARES_T*, previnds, currinds);
  1650. }
  1651. PAR_SWAP(uint8_t*, prevrowcells, currrowcells);
  1652. PAR_SWAP(PAR_MSQUARES_T*, prevrowinds, currrowinds);
  1653. }
  1654. free(prevrowinds);
  1655. free(prevrowcells);
  1656. free(pixels);
  1657. if (flags & PAR_MSQUARES_CLEAN) {
  1658. par_msquares__repair_tjunctions(mlist);
  1659. }
  1660. for (int m = 0; m < mlist->nmeshes; m++) {
  1661. par_msquares__mesh* mesh = mlist->meshes[m];
  1662. par__uint16list_free(mesh->tjunctions);
  1663. }
  1664. if (!(flags & PAR_MSQUARES_SIMPLIFY)) {
  1665. par_msquares__finalize(mlist);
  1666. return mlist;
  1667. }
  1668. uint8_t* simplification_blocks = PAR_CALLOC(uint8_t, nrows * ncols);
  1669. uint32_t* simplification_tris = PAR_CALLOC(uint32_t, nrows * ncols);
  1670. uint8_t* simplification_ntris = PAR_CALLOC(uint8_t, nrows * ncols);
  1671. // Perform quick-n-dirty simplification by iterating two rows at a time.
  1672. // In no way does this create the simplest possible mesh, but at least it's
  1673. // fast and easy.
  1674. for (uint32_t color = 0; color < (uint32_t) ncolors; color++) {
  1675. par_msquares__mesh* mesh = mlist->meshes[color];
  1676. // Populate the per-mesh info grids.
  1677. int ntris = 0;
  1678. for (int row = 0; row < nrows; row++) {
  1679. for (int col = 0; col < ncols; col++) {
  1680. int cell = ncols * row + col;
  1681. uint32_t colors = simplification_words[cell * 2];
  1682. uint32_t counts = simplification_words[cell * 2 + 1];
  1683. int ncelltris = 0;
  1684. int ncorners = 0;
  1685. if ((colors & 0xff) == color) {
  1686. ncelltris = counts & 0xff;
  1687. ncorners++;
  1688. }
  1689. if (((colors >> 8) & 0xff) == color) {
  1690. ncelltris += (counts >> 8) & 0xff;
  1691. ncorners++;
  1692. }
  1693. if (((colors >> 16) & 0xff) == color) {
  1694. ncelltris += (counts >> 16) & 0xff;
  1695. ncorners++;
  1696. }
  1697. if (((colors >> 24) & 0xff) == color) {
  1698. ncelltris += (counts >> 24) & 0xff;
  1699. ncorners++;
  1700. }
  1701. simplification_ntris[cell] = ncelltris;
  1702. simplification_tris[cell] = ntris;
  1703. simplification_blocks[cell] = ncorners == 4;
  1704. ntris += ncelltris;
  1705. }
  1706. }
  1707. // First figure out how many triangles we can eliminate.
  1708. int in_run = 0, start_run;
  1709. int neliminated_triangles = 0;
  1710. for (int row = 0; row < nrows - 1; row += 2) {
  1711. for (int col = 0; col < ncols; col++) {
  1712. int cell = ncols * row + col;
  1713. int a = simplification_blocks[cell];
  1714. int b = simplification_blocks[cell + ncols];
  1715. if (a && b) {
  1716. if (!in_run) {
  1717. in_run = 1;
  1718. start_run = col;
  1719. }
  1720. continue;
  1721. }
  1722. if (in_run) {
  1723. in_run = 0;
  1724. int run_width = col - start_run;
  1725. neliminated_triangles += run_width * 4 - 2;
  1726. }
  1727. }
  1728. if (in_run) {
  1729. in_run = 0;
  1730. int run_width = ncols - start_run;
  1731. neliminated_triangles += run_width * 4 - 2;
  1732. }
  1733. }
  1734. if (neliminated_triangles == 0) {
  1735. continue;
  1736. }
  1737. // Build a new index array cell-by-cell. If any given cell is 'F' and
  1738. // its neighbor to the south is also 'F', then it's part of a run.
  1739. int nnewtris = mesh->ntriangles - neliminated_triangles;
  1740. PAR_MSQUARES_T* newtris = PAR_CALLOC(PAR_MSQUARES_T, nnewtris * 3);
  1741. PAR_MSQUARES_T* pnewtris = newtris;
  1742. in_run = 0;
  1743. PAR_MSQUARES_T* tris = mesh->triangles;
  1744. for (int row = 0; row < nrows - 1; row += 2) {
  1745. for (int col = 0; col < ncols; col++) {
  1746. int cell = ncols * row + col;
  1747. int south = cell + ncols;
  1748. int a = simplification_blocks[cell];
  1749. int b = simplification_blocks[south];
  1750. if (a && b) {
  1751. if (!in_run) {
  1752. in_run = 1;
  1753. start_run = col;
  1754. }
  1755. continue;
  1756. }
  1757. if (in_run) {
  1758. in_run = 0;
  1759. int nw_cell = ncols * row + start_run;
  1760. int ne_cell = ncols * row + col - 1;
  1761. int sw_cell = nw_cell + ncols;
  1762. int se_cell = ne_cell + ncols;
  1763. int nw_tri = simplification_tris[nw_cell];
  1764. int ne_tri = simplification_tris[ne_cell];
  1765. int sw_tri = simplification_tris[sw_cell];
  1766. int se_tri = simplification_tris[se_cell];
  1767. int nw_corner = nw_tri * 3 + 5;
  1768. int ne_corner = ne_tri * 3 + 2;
  1769. int sw_corner = sw_tri * 3 + 0;
  1770. int se_corner = se_tri * 3 + 1;
  1771. *pnewtris++ = tris[nw_corner];
  1772. *pnewtris++ = tris[sw_corner];
  1773. *pnewtris++ = tris[se_corner];
  1774. *pnewtris++ = tris[se_corner];
  1775. *pnewtris++ = tris[ne_corner];
  1776. *pnewtris++ = tris[nw_corner];
  1777. }
  1778. int ncelltris = simplification_ntris[cell];
  1779. int celltri = simplification_tris[cell];
  1780. for (int t = 0; t < ncelltris; t++, celltri++) {
  1781. *pnewtris++ = tris[celltri * 3];
  1782. *pnewtris++ = tris[celltri * 3 + 1];
  1783. *pnewtris++ = tris[celltri * 3 + 2];
  1784. }
  1785. ncelltris = simplification_ntris[south];
  1786. celltri = simplification_tris[south];
  1787. for (int t = 0; t < ncelltris; t++, celltri++) {
  1788. *pnewtris++ = tris[celltri * 3];
  1789. *pnewtris++ = tris[celltri * 3 + 1];
  1790. *pnewtris++ = tris[celltri * 3 + 2];
  1791. }
  1792. }
  1793. if (in_run) {
  1794. in_run = 0;
  1795. int nw_cell = ncols * row + start_run;
  1796. int ne_cell = ncols * row + ncols - 1;
  1797. int sw_cell = nw_cell + ncols;
  1798. int se_cell = ne_cell + ncols;
  1799. int nw_tri = simplification_tris[nw_cell];
  1800. int ne_tri = simplification_tris[ne_cell];
  1801. int sw_tri = simplification_tris[sw_cell];
  1802. int se_tri = simplification_tris[se_cell];
  1803. int nw_corner = nw_tri * 3 + 5;
  1804. int ne_corner = ne_tri * 3 + 2;
  1805. int sw_corner = sw_tri * 3 + 0;
  1806. int se_corner = se_tri * 3 + 1;
  1807. *pnewtris++ = tris[nw_corner];
  1808. *pnewtris++ = tris[sw_corner];
  1809. *pnewtris++ = tris[se_corner];
  1810. *pnewtris++ = tris[se_corner];
  1811. *pnewtris++ = tris[ne_corner];
  1812. *pnewtris++ = tris[nw_corner];
  1813. }
  1814. }
  1815. mesh->ntriangles -= neliminated_triangles;
  1816. free(mesh->triangles);
  1817. mesh->triangles = newtris;
  1818. }
  1819. free(simplification_blocks);
  1820. free(simplification_ntris);
  1821. free(simplification_tris);
  1822. free(simplification_words);
  1823. par_msquares__finalize(mlist);
  1824. for (int i = 0; i < mlist->nmeshes; i++) {
  1825. par_remove_unreferenced_verts(mlist->meshes[i]);
  1826. }
  1827. return mlist;
  1828. }
  1829. void par_msquares_free_boundary(par_msquares_boundary* polygon)
  1830. {
  1831. free(polygon->points);
  1832. free(polygon->chains);
  1833. free(polygon->lengths);
  1834. free(polygon);
  1835. }
  1836. typedef struct par__hedge_s {
  1837. uint32_t key;
  1838. struct par__hvert_s* endvert;
  1839. struct par__hedge_s* opposite;
  1840. struct par__hedge_s* next;
  1841. struct par__hedge_s* prev;
  1842. } par__hedge;
  1843. typedef struct par__hvert_s {
  1844. par__hedge* incoming;
  1845. } par__hvert;
  1846. typedef struct {
  1847. par_msquares_mesh const* mesh;
  1848. par__hvert* verts;
  1849. par__hedge* edges;
  1850. par__hedge** sorted_edges;
  1851. } par__hemesh;
  1852. static int par__hedge_cmp(const void *arg0, const void *arg1)
  1853. {
  1854. par__hedge* he0 = *((par__hedge**) arg0);
  1855. par__hedge* he1 = *((par__hedge**) arg1);
  1856. if (he0->key < he1->key) return -1;
  1857. if (he0->key > he1->key) return 1;
  1858. return 0;
  1859. }
  1860. static par__hedge* par__hedge_find(par__hemesh* hemesh, uint32_t key)
  1861. {
  1862. par__hedge target = {0};
  1863. target.key = key;
  1864. par__hedge* ptarget = &target;
  1865. int nedges = hemesh->mesh->ntriangles * 3;
  1866. par__hedge** result = (par__hedge**) bsearch(&ptarget, hemesh->sorted_edges,
  1867. nedges, sizeof(par__hedge*), par__hedge_cmp);
  1868. return result ? *result : 0;
  1869. }
  1870. static uint32_t par__hedge_key(par__hvert* a, par__hvert* b, par__hvert* s)
  1871. {
  1872. uint32_t ai = a - s;
  1873. uint32_t bi = b - s;
  1874. return (ai << 16) | bi;
  1875. }
  1876. par_msquares_boundary* par_msquares_extract_boundary(
  1877. par_msquares_mesh const* mesh)
  1878. {
  1879. par_msquares_boundary* result = PAR_CALLOC(par_msquares_boundary, 1);
  1880. par__hemesh hemesh = {0};
  1881. hemesh.mesh = mesh;
  1882. int nedges = mesh->ntriangles * 3;
  1883. // Populate all fields of verts and edges, except opposite.
  1884. hemesh.edges = PAR_CALLOC(par__hedge, nedges);
  1885. par__hvert* hverts = hemesh.verts = PAR_CALLOC(par__hvert, mesh->npoints);
  1886. par__hedge* edge = hemesh.edges;
  1887. PAR_MSQUARES_T const* tri = mesh->triangles;
  1888. for (int n = 0; n < mesh->ntriangles; n++, edge += 3, tri += 3) {
  1889. edge[0].endvert = hverts + tri[1];
  1890. edge[1].endvert = hverts + tri[2];
  1891. edge[2].endvert = hverts + tri[0];
  1892. hverts[tri[1]].incoming = edge + 0;
  1893. hverts[tri[2]].incoming = edge + 1;
  1894. hverts[tri[0]].incoming = edge + 2;
  1895. edge[0].next = edge + 1;
  1896. edge[1].next = edge + 2;
  1897. edge[2].next = edge + 0;
  1898. edge[0].prev = edge + 2;
  1899. edge[1].prev = edge + 0;
  1900. edge[2].prev = edge + 1;
  1901. edge[0].key = par__hedge_key(edge[2].endvert, edge[0].endvert, hverts);
  1902. edge[1].key = par__hedge_key(edge[0].endvert, edge[1].endvert, hverts);
  1903. edge[2].key = par__hedge_key(edge[1].endvert, edge[2].endvert, hverts);
  1904. }
  1905. // Sort the edges according to their key.
  1906. hemesh.sorted_edges = PAR_CALLOC(par__hedge*, mesh->ntriangles * 3);
  1907. for (int n = 0; n < nedges; n++) {
  1908. hemesh.sorted_edges[n] = hemesh.edges + n;
  1909. }
  1910. qsort(hemesh.sorted_edges, nedges, sizeof(par__hedge*), par__hedge_cmp);
  1911. // Populate the "opposite" field in each edge.
  1912. for (int n = 0; n < nedges; n++) {
  1913. par__hedge* edge = hemesh.edges + n;
  1914. par__hedge* prev = edge->prev;
  1915. par__hvert* start = edge->endvert;
  1916. par__hvert* end = prev->endvert;
  1917. uint32_t key = par__hedge_key(start, end, hverts);
  1918. edge->opposite = par__hedge_find(&hemesh, key);
  1919. }
  1920. // Re-use the sorted_edges array, filling it with boundary edges only.
  1921. // Also create a mapping table to consolidate all boundary verts.
  1922. int nborders = 0;
  1923. for (int n = 0; n < nedges; n++) {
  1924. par__hedge* edge = hemesh.edges + n;
  1925. if (!edge->opposite) {
  1926. hemesh.sorted_edges[nborders++] = edge;
  1927. }
  1928. }
  1929. // Allocate for the worst case (all separate triangles).
  1930. // We'll adjust the lengths later.
  1931. result->nchains = nborders / 3;
  1932. result->npoints = nborders + result->nchains;
  1933. result->points = PAR_CALLOC(float, 2 * result->npoints);
  1934. result->chains = PAR_CALLOC(float*, result->nchains);
  1935. result->lengths = PAR_CALLOC(PAR_MSQUARES_T, result->nchains);
  1936. // Iterate over each polyline.
  1937. edge = hemesh.sorted_edges[0];
  1938. int pt = 0;
  1939. int nwritten = 0;
  1940. int nchains = 0;
  1941. while (1) {
  1942. float* points = result->points;
  1943. par__hedge* orig = edge;
  1944. PAR_MSQUARES_T index = edge->prev->endvert - hverts;
  1945. result->chains[nchains] = points + pt;
  1946. result->lengths[nchains]++;
  1947. points[pt++] = mesh->points[index * mesh->dim];
  1948. points[pt++] = mesh->points[index * mesh->dim + 1];
  1949. while (1) {
  1950. index = edge->endvert - hverts;
  1951. edge->key = 0;
  1952. nwritten++;
  1953. result->lengths[nchains]++;
  1954. points[pt++] = mesh->points[index * mesh->dim];
  1955. points[pt++] = mesh->points[index * mesh->dim + 1];
  1956. par__hedge* next = edge->next;
  1957. while (next != edge) {
  1958. if (!next->opposite) {
  1959. break;
  1960. }
  1961. next = next->opposite->next;
  1962. }
  1963. edge = next;
  1964. if (edge == orig) {
  1965. break;
  1966. }
  1967. }
  1968. nchains++;
  1969. if (nwritten >= nborders) {
  1970. break;
  1971. }
  1972. for (int i = 0; i < nborders; i++) {
  1973. edge = hemesh.sorted_edges[i];
  1974. if (edge->key) {
  1975. break;
  1976. }
  1977. }
  1978. }
  1979. result->npoints = pt / 2;
  1980. result->nchains = nchains;
  1981. free(hemesh.verts);
  1982. free(hemesh.edges);
  1983. free(hemesh.sorted_edges);
  1984. return result;
  1985. }
  1986. #endif // PAR_MSQUARES_IMPLEMENTATION
  1987. #endif // PAR_MSQUARES_H
  1988. // par_msquares is distributed under the MIT license:
  1989. //
  1990. // Copyright (c) 2019 Philip Rideout
  1991. //
  1992. // Permission is hereby granted, free of charge, to any person obtaining a copy
  1993. // of this software and associated documentation files (the "Software"), to deal
  1994. // in the Software without restriction, including without limitation the rights
  1995. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  1996. // copies of the Software, and to permit persons to whom the Software is
  1997. // furnished to do so, subject to the following conditions:
  1998. //
  1999. // The above copyright notice and this permission notice shall be included in
  2000. // all copies or substantial portions of the Software.
  2001. //
  2002. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2003. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2004. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2005. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2006. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  2007. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  2008. // SOFTWARE.