mi_spans.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. /* This file is part of the GNU libxmi package.
  2. Copyright (C) 1985, 1986, 1987, 1988, 1989, X Consortium. For an
  3. associated permission notice, see the accompanying file README-X.
  4. GNU enhancements Copyright (C) 1998, 1999, 2000, 2005, Free Software
  5. Foundation, Inc.
  6. The GNU libxmi package is free software. You may redistribute it
  7. and/or modify it under the terms of the GNU General Public License as
  8. published by the Free Software foundation; either version 2, or (at your
  9. option) any later version.
  10. The GNU libxmi package is distributed in the hope that it will be
  11. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. General Public License for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with the GNU plotutils package; see the file COPYING. If not, write to
  16. the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
  17. Boston, MA 02110-1301, USA. */
  18. /* This module provides several public functions: miNewPaintedSet(),
  19. miAddSpansToPaintedSet(), miUniquifyPaintedSet(), miClearPaintedSet(),
  20. miDeletePaintedSet(). They maintain a structure called a miPaintedSet,
  21. which is essentially an array of SpanGroup structures, one per pixel
  22. value. A SpanGroup is essentially an unsorted list of Spans's. A Spans
  23. is a list of spans (i.e. horizontal ranges) of miPoints, sorted so that
  24. the starting points have increasing y-values. See mi_spans.h.
  25. Internally, each libxmi drawing function paints to a miPaintedSet by
  26. calling miAddSpansToPaintedSet() on one or more Spans's. This function
  27. adds a Spans to a miPaintedSet, being careful first to remove each from
  28. the miPaintedSet each pixel in the Spans, if it has previously been
  29. painted another color. However, for efficiency it does not check
  30. whether a pixel in the Spans has been previously painted the same color.
  31. So while the drawing function is being called, the Spans in any one of
  32. the PaintedSet's SpanGroups may overlap. But different SpanGroups do
  33. not overlap. That is an invariant.
  34. After all calls to miAddSpansToPaintedSet() are completed, duplicate
  35. pixels are resolved by invoking miUniquifyPaintedSet(). That takes
  36. place in the API wrappers in mi_api.c, just before the drawing function
  37. returns.
  38. The function miCopyPaintedSetToCanvas(), in mi_canvas.c, can copy the
  39. contents of a miPaintedSet, i.e. its spans of painted miPoints, to a
  40. miCanvas structure. Sophisticated pixel merging is supported. It would
  41. be easy to write other functions that copy pixels out of a
  42. miPaintedSet. */
  43. /* Original version written by Joel McCormack, Summer 1989.
  44. Hacked by Robert S. Maier, 1998-1999. */
  45. #include "sys-defines.h"
  46. #include "extern.h"
  47. #include "xmi.h"
  48. #include "mi_spans.h"
  49. #include "mi_api.h"
  50. /* spans in a Spans are sorted by y, so these give ymin, ymax for a
  51. nonempty Spans */
  52. #define YMIN(spans) (spans->points[0].y)
  53. #define YMAX(spans) (spans->points[spans->count-1].y)
  54. /* internal functions */
  55. static SpanGroup * miNewSpanGroup (miPixel pixel);
  56. static int miUniquifySpansX (const Spans *spans, miPoint *newPoints, unsigned int *newWidths);
  57. static void miAddSpansToSpanGroup (const Spans *spans, SpanGroup *spanGroup);
  58. static void miDeleteSpanGroup (SpanGroup *spanGroup);
  59. static void miQuickSortSpansX (miPoint *points, unsigned int *widths, int numSpans);
  60. static void miSubtractSpans (SpanGroup *spanGroup, const Spans *sub);
  61. static void miUniquifySpanGroup (SpanGroup *spanGroup);
  62. /* The following functions are the public functions of this module. */
  63. miPaintedSet *
  64. miNewPaintedSet (void)
  65. {
  66. miPaintedSet *paintedSet;
  67. paintedSet = (miPaintedSet *)mi_xmalloc (sizeof(miPaintedSet));
  68. paintedSet->groups = (SpanGroup **)NULL; /* pointer-to-SpanGroup slots */
  69. paintedSet->size = 0; /* slots allocated */
  70. paintedSet->ngroups = 0; /* slots filled */
  71. return paintedSet;
  72. }
  73. /* Add a Spans to a miPaintedSet's SpanGroup for a specified pixel values,
  74. and also subtract it from the SpanGroups for all other pixel values. */
  75. void
  76. miAddSpansToPaintedSet (const Spans *spans, miPaintedSet *paintedSet, miPixel pixel)
  77. {
  78. bool found = false;
  79. int i;
  80. SpanGroup *spanGroup;
  81. if (spans->count == 0)
  82. return;
  83. for (i = 0; i < paintedSet->ngroups; i++)
  84. {
  85. miPixel stored_pixel;
  86. stored_pixel = paintedSet->groups[i]->pixel;
  87. if (MI_SAME_PIXEL(pixel, stored_pixel))
  88. {
  89. found = true; /* have a spanGroup for this pixel value */
  90. break;
  91. }
  92. }
  93. if (!found)
  94. {
  95. if (paintedSet->ngroups == paintedSet->size)
  96. /* expand array of SpanGroups */
  97. {
  98. int old_size = paintedSet->size;
  99. int new_size = 2 * (old_size + 8);
  100. if (old_size == 0)
  101. paintedSet->groups = (SpanGroup **)
  102. mi_xmalloc(new_size * sizeof(SpanGroup *));
  103. else
  104. paintedSet->groups = (SpanGroup **)
  105. mi_xrealloc(paintedSet->groups, new_size * sizeof(SpanGroup *));
  106. paintedSet->size = new_size;
  107. }
  108. /* create a SpanGroup for this pixel value */
  109. i = paintedSet->ngroups;
  110. paintedSet->groups[i] = miNewSpanGroup (pixel);
  111. paintedSet->ngroups++;
  112. }
  113. spanGroup = paintedSet->groups[i];
  114. miAddSpansToSpanGroup (spans, spanGroup);
  115. /* subtract Spans from all other SpanGroups */
  116. for (i = 0; i < paintedSet->ngroups; i++)
  117. {
  118. SpanGroup *otherGroup;
  119. otherGroup = paintedSet->groups[i];
  120. if (otherGroup == spanGroup)
  121. continue;
  122. miSubtractSpans (otherGroup, spans);
  123. }
  124. }
  125. /* Deallocate all of a miPaintedSet's SpanGroups, including the points and
  126. width arrays that are part of its component Spans's. So it will
  127. effectively become the empty set, as if it had been newly created. */
  128. void
  129. miClearPaintedSet (miPaintedSet *paintedSet)
  130. {
  131. int i;
  132. if (paintedSet == (miPaintedSet *)NULL)
  133. return;
  134. for (i = 0; i < paintedSet->ngroups; i++)
  135. miDeleteSpanGroup (paintedSet->groups[i]);
  136. if (paintedSet->size > 0)
  137. free (paintedSet->groups);
  138. paintedSet->size = 0; /* slots allocated */
  139. paintedSet->ngroups = 0; /* slots filled */
  140. }
  141. /* Deallocate a miPaintedSet, including the points and width arrays that
  142. are part of its component Spans's. */
  143. void
  144. miDeletePaintedSet (miPaintedSet *paintedSet)
  145. {
  146. int i;
  147. if (paintedSet == (miPaintedSet *)NULL)
  148. return;
  149. for (i = 0; i < paintedSet->ngroups; i++)
  150. miDeleteSpanGroup (paintedSet->groups[i]);
  151. if (paintedSet->size > 0)
  152. free (paintedSet->groups);
  153. free (paintedSet);
  154. }
  155. /* `Uniquify' a miPaintedSet, i.e. uniquify each of its SpanGroups (see
  156. below). */
  157. void
  158. miUniquifyPaintedSet (miPaintedSet *paintedSet)
  159. {
  160. int i;
  161. if (paintedSet == (miPaintedSet *)NULL)
  162. return;
  163. for (i = 0; i < paintedSet->ngroups; i++)
  164. {
  165. if (paintedSet->groups[i]->count > 0)
  166. {
  167. miUniquifySpanGroup (paintedSet->groups[i]);
  168. }
  169. }
  170. }
  171. /* Create and initialize a SpanGroup, i.e. an unsorted list of Spans's. */
  172. static SpanGroup *
  173. miNewSpanGroup (miPixel pixel)
  174. {
  175. SpanGroup *spanGroup;
  176. spanGroup = (SpanGroup *)mi_xmalloc (sizeof(SpanGroup));
  177. spanGroup->pixel = pixel; /* pixel to be used */
  178. spanGroup->size = 0; /* slots allocated */
  179. spanGroup->count = 0; /* slots filled */
  180. spanGroup->group = (Spans *)NULL; /* slots for Spans's */
  181. spanGroup->ymin = INT_MAX; /* min over slots */
  182. spanGroup->ymax = INT_MIN; /* max over slots */
  183. return spanGroup;
  184. }
  185. /* Add a Spans to a SpanGroup, by tacking it on the end; update SpanGroup's
  186. ymin, ymax. */
  187. static void
  188. miAddSpansToSpanGroup (const Spans *spans, SpanGroup *spanGroup)
  189. {
  190. int ymin, ymax;
  191. if (spans->count == 0)
  192. return;
  193. if (spanGroup->size == spanGroup->count)
  194. /* expand SpanGroup */
  195. {
  196. spanGroup->size = (spanGroup->size + 8) * 2;
  197. spanGroup->group = (Spans *)
  198. mi_xrealloc(spanGroup->group, sizeof(Spans) * spanGroup->size);
  199. }
  200. /* tack Spans onto end of SpanGroup, update SpanGroup's ymin and ymax */
  201. spanGroup->group[spanGroup->count] = *spans;
  202. (spanGroup->count)++;
  203. ymin = YMIN(spans);
  204. if (ymin < spanGroup->ymin)
  205. spanGroup->ymin = ymin;
  206. ymax = YMAX(spans);
  207. if (ymax > spanGroup->ymax)
  208. spanGroup->ymax = ymax;
  209. }
  210. /* Delete a SpanGroup, including the point and width arrays that are part
  211. of each Spans. */
  212. static void
  213. miDeleteSpanGroup (SpanGroup *spanGroup)
  214. {
  215. int i;
  216. if (spanGroup == (SpanGroup *)NULL)
  217. return;
  218. for (i = 0; i < spanGroup->count; i++)
  219. {
  220. /* free spanGroup->group[i], which is a Spans */
  221. free (spanGroup->group[i].points);
  222. free (spanGroup->group[i].widths);
  223. }
  224. if (spanGroup->group)
  225. free (spanGroup->group);
  226. free (spanGroup);
  227. }
  228. /* Subtract a Spans from a SpanGroup, i.e. from each of its Spans's; update
  229. SpanGroup's ymin, ymax. */
  230. static void
  231. miSubtractSpans (SpanGroup *spanGroup, const Spans *sub)
  232. {
  233. int i, subCount, spansCount;
  234. int ymin, ymax, xmin, xmax;
  235. Spans *spans;
  236. miPoint *subPt, *spansPt;
  237. unsigned int *subWid, *spansWid;
  238. int extra;
  239. bool gross_change = false;
  240. if (sub->count == 0) /* nothing to do */
  241. return;
  242. /* y range of Spans to be subtracted */
  243. ymin = YMIN(sub);
  244. ymax = YMAX(sub);
  245. /* loop through all Spans's in SpanGroup */
  246. spans = spanGroup->group;
  247. for (i = spanGroup->count; i > 0; i--, spans++)
  248. {
  249. if (spans->count == 0)
  250. continue;
  251. /* look only at Spans's with y ranges that overlap with `sub' */
  252. if (YMIN(spans) <= ymax && ymin <= YMAX(spans))
  253. {
  254. /* count, start points, and widths for `sub' */
  255. subCount = sub->count;
  256. subPt = sub->points;
  257. subWid = sub->widths;
  258. /* count, start points, and widths for current Spans */
  259. spansCount = spans->count;
  260. spansPt = spans->points;
  261. spansWid = spans->widths;
  262. extra = 0; /* extra span slots available in Spans */
  263. for (;;)
  264. /* look at pairs of spans, one from each Spans, that have the
  265. same value for y (break out when one or the other Spans is
  266. exhausted) */
  267. {
  268. while (spansCount && spansPt->y < subPt->y)
  269. {
  270. spansPt++;
  271. spansWid++;
  272. spansCount--;
  273. }
  274. if (!spansCount)
  275. break;
  276. while (subCount && subPt->y < spansPt->y)
  277. {
  278. subPt++;
  279. subWid++;
  280. subCount--;
  281. }
  282. if (!subCount)
  283. break;
  284. if (subPt->y == spansPt->y)
  285. /* the two spans are at same y value, analyse in detail */
  286. {
  287. xmin = subPt->x;
  288. xmax = xmin + (int)(*subWid); /* just right of sub span */
  289. if (xmin >= spansPt->x + (int)(*spansWid)
  290. || spansPt->x >= xmax)
  291. /* non-overlapping, do nothing */
  292. {
  293. ;
  294. }
  295. else if (xmin <= spansPt->x)
  296. /* span to be subtracted begins at the same point, or
  297. to the left */
  298. {
  299. if (xmax >= spansPt->x + (int)(*spansWid))
  300. /* span to be subtracted ends at the same point,
  301. or to the right; delete this span by downshifting */
  302. {
  303. memmove (spansPt, spansPt + 1,
  304. sizeof(miPoint) * (spansCount - 1));
  305. memmove (spansWid, spansWid + 1,
  306. sizeof(unsigned int) * (spansCount - 1));
  307. spansPt--;
  308. spansWid--;
  309. spans->count--;
  310. extra++;
  311. gross_change = true; /* span vanished */
  312. }
  313. else
  314. /* span to be subtracted ends to the left of this
  315. one's ending point; alter ending point and width */
  316. {
  317. *spansWid =
  318. *spansWid - (unsigned int)(xmax - spansPt->x);
  319. spansPt->x = xmax;
  320. }
  321. }
  322. else
  323. /* span to be subtracted overlaps with this one, and
  324. begins to the right of this one */
  325. {
  326. if (xmax >= spansPt->x + (int)*spansWid)
  327. /* span to be subtracted ends at the same point, or
  328. to the right; just update width */
  329. *spansWid = (unsigned int)(xmin - spansPt->x);
  330. else
  331. /* hard case: must split the span */
  332. {
  333. #define EXTRA 8
  334. if (extra == 0)
  335. /* reallocate; create EXTRA new span slots */
  336. {
  337. miPoint *newPt;
  338. unsigned int *newwid;
  339. newPt = (miPoint *)mi_xrealloc (spans->points,
  340. (spans->count + EXTRA)*sizeof(miPoint));
  341. spansPt = newPt + (spansPt - spans->points);
  342. spans->points = newPt;
  343. newwid = (unsigned int *)mi_xrealloc (spans->widths,
  344. (spans->count + EXTRA)*sizeof(unsigned int));
  345. spansWid = newwid + (spansWid - spans->widths);
  346. spans->widths = newwid;
  347. extra = EXTRA;
  348. }
  349. /* downshift; create two new spans as replacement */
  350. memmove (spansPt + 1, spansPt,
  351. sizeof(miPoint) * spansCount);
  352. memmove (spansWid + 1, spansWid,
  353. sizeof(unsigned int) * spansCount);
  354. spans->count++;
  355. extra--;
  356. /* first new span */
  357. *spansWid = (unsigned int)(xmin - spansPt->x);
  358. spansWid++;
  359. spansPt++;
  360. /* second new span */
  361. *spansWid = *spansWid - (unsigned int)(xmax - spansPt->x);
  362. spansPt->x = xmax;
  363. }
  364. }
  365. } /* end of same-value-of-y computations */
  366. /* on to next span in the Spans */
  367. spansPt++;
  368. spansWid++;
  369. spansCount--;
  370. }
  371. }
  372. }
  373. if (gross_change)
  374. /* at least one span vanished; recompute SpanGroup's ymin, ymax */
  375. {
  376. ymax = INT_MIN;
  377. ymin = INT_MAX;
  378. /* loop through all Spans's in SpanGroup */
  379. spans = spanGroup->group;
  380. for (i = spanGroup->count; i > 0; i--, spans++)
  381. {
  382. int ymin_spans, ymax_spans;
  383. if (spans->count == 0)
  384. continue;
  385. ymin_spans = YMIN(spans);
  386. ymax_spans = YMAX(spans);
  387. if (ymin_spans < ymin)
  388. ymin = ymin_spans;
  389. if (ymax_spans > ymax)
  390. ymax = ymax_spans;
  391. }
  392. spanGroup->ymin = ymin;
  393. spanGroup->ymax = ymax;
  394. }
  395. }
  396. /* `Uniquify' a SpanGroup: merge all its Spans's into a single Spans, which
  397. will be sorted on x as well as on y. */
  398. static void
  399. miUniquifySpanGroup (SpanGroup *spanGroup)
  400. {
  401. int i;
  402. Spans *spans;
  403. Spans *yspans;
  404. int *ysizes;
  405. int ymin, ylength;
  406. /* the new single Spans */
  407. miPoint *points;
  408. unsigned int *widths;
  409. int count;
  410. if (spanGroup->count == 0)
  411. return;
  412. /* Special case : ymin > ymax, so the Spans's in the SpanGroup, no matter
  413. how numerous, must be empty (and can't contain point or width arrays). */
  414. if (spanGroup->ymin > spanGroup->ymax)
  415. {
  416. spanGroup->count = 0;
  417. return;
  418. }
  419. /* Yuck. Gross. Radix sort into y buckets, then sort x and uniquify */
  420. /* This seems to be the fastest thing to do. I've tried sorting on
  421. both x and y at the same time rather than creating into all those
  422. y buckets, but it was somewhat slower. */
  423. ymin = spanGroup->ymin;
  424. ylength = spanGroup->ymax - ymin + 1;
  425. /* allocate Spans's for y buckets (one Spans for every scanline);
  426. ysizes[] is number of allocated Span slots in each bucket */
  427. yspans = (Spans *)mi_xmalloc (ylength * sizeof(Spans));
  428. ysizes = (int *)mi_xmalloc (ylength * sizeof(int));
  429. for (i = 0; i < ylength; i++)
  430. {
  431. ysizes[i] = 0;
  432. yspans[i].count = 0;
  433. yspans[i].points = (miPoint *)NULL;
  434. yspans[i].widths = (unsigned int *)NULL;
  435. }
  436. /* go through every single span and put it into the correct y bucket */
  437. count = 0;
  438. for (i = 0, spans = spanGroup->group;
  439. i < spanGroup->count; i++, spans++)
  440. {
  441. int j, index;
  442. for (j = 0, points = spans->points, widths = spans->widths;
  443. j < spans->count; j++, points++, widths++)
  444. {
  445. index = points->y - ymin;
  446. if (index >= 0 && index < ylength) /* paranoia */
  447. {
  448. Spans *newspans = &(yspans[index]);
  449. if (newspans->count == ysizes[index])
  450. /* expand bucket arrays by reallocating */
  451. {
  452. ysizes[index] = (ysizes[index] + 8) * 2;
  453. newspans->points
  454. = (miPoint *)mi_xrealloc (newspans->points,
  455. ysizes[index] * sizeof(miPoint));
  456. newspans->widths
  457. = (unsigned int *)mi_xrealloc (newspans->widths,
  458. ysizes[index] * sizeof(unsigned int));
  459. }
  460. newspans->points[newspans->count] = *points;
  461. newspans->widths[newspans->count] = *widths;
  462. (newspans->count)++;
  463. } /* if y value of span in range */
  464. } /* for j through spans */
  465. count += spans->count;
  466. } /* for i through Spans */
  467. free (ysizes);
  468. /* now sort each bucket by x and uniquify it into new Spans */
  469. points = (miPoint *)mi_xmalloc (count * sizeof(miPoint));
  470. widths = (unsigned int *)mi_xmalloc (count * sizeof(unsigned int));
  471. count = 0;
  472. for (i = 0; i < ylength; i++)
  473. {
  474. int ycount = yspans[i].count;
  475. if (ycount > 0)
  476. {
  477. if (ycount > 1)
  478. /* sort the >1 spans at this value of y */
  479. {
  480. miQuickSortSpansX (yspans[i].points, yspans[i].widths, ycount);
  481. count += miUniquifySpansX
  482. (&(yspans[i]), &(points[count]), &(widths[count]));
  483. }
  484. else
  485. /* just a single span at this value of y */
  486. {
  487. points[count] = yspans[i].points[0];
  488. widths[count] = yspans[i].widths[0];
  489. count++;
  490. }
  491. free (yspans[i].points);
  492. free (yspans[i].widths);
  493. }
  494. }
  495. free (yspans);
  496. /* free SpanGroup's original Spans's, including Span arrays */
  497. for (i = 0; i < spanGroup->count; i++)
  498. {
  499. free (spanGroup->group[i].points);
  500. free (spanGroup->group[i].widths);
  501. }
  502. /* SpanGroup now has only a single Spans */
  503. spanGroup->count = 1;
  504. spanGroup->group[0].points = points;
  505. spanGroup->group[0].widths = widths;
  506. spanGroup->group[0].count = count;
  507. }
  508. /* Sort each span in a Spans by x. Called only if numSpans > 1. */
  509. static void
  510. miQuickSortSpansX (miPoint *points, unsigned int *widths, int numSpans)
  511. {
  512. int x;
  513. int i, j, m;
  514. miPoint *r;
  515. #define ExchangeSpans(a, b) \
  516. { \
  517. miPoint tpt; \
  518. unsigned int tw; \
  519. \
  520. tpt = points[a]; points[a] = points[b]; points[b] = tpt; \
  521. tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
  522. }
  523. do
  524. {
  525. if (numSpans < 9)
  526. /* do insertion sort */
  527. {
  528. int xprev;
  529. xprev = points[0].x;
  530. i = 1;
  531. do /* while i != numSpans */
  532. {
  533. x = points[i].x;
  534. if (xprev > x)
  535. {
  536. /* points[i] is out of order. Move into proper location. */
  537. miPoint tpt;
  538. unsigned int tw;
  539. int k;
  540. for (j = 0; x >= points[j].x; j++)
  541. {
  542. }
  543. tpt = points[i];
  544. tw = widths[i];
  545. for (k = i; k != j; k--)
  546. {
  547. points[k] = points[k-1];
  548. widths[k] = widths[k-1];
  549. }
  550. points[j] = tpt;
  551. widths[j] = tw;
  552. x = points[i].x;
  553. } /* if out of order */
  554. xprev = x;
  555. i++;
  556. } while (i != numSpans);
  557. /* end of insertion sort */
  558. return;
  559. }
  560. /* Choose partition element, stick in location 0 */
  561. m = numSpans / 2;
  562. if (points[m].x > points[0].x)
  563. ExchangeSpans(m, 0);
  564. if (points[m].x > points[numSpans-1].x)
  565. ExchangeSpans(m, numSpans-1);
  566. if (points[m].x > points[0].x)
  567. ExchangeSpans(m, 0);
  568. x = points[0].x;
  569. /* Partition array */
  570. i = 0;
  571. j = numSpans;
  572. do
  573. {
  574. r = &(points[i]);
  575. do
  576. {
  577. r++;
  578. i++;
  579. }
  580. while (i != numSpans && r->x < x)
  581. ;
  582. r = &(points[j]);
  583. do
  584. {
  585. r--;
  586. j--;
  587. }
  588. while (x < r->x);
  589. if (i < j) ExchangeSpans(i, j);
  590. }
  591. while (i < j);
  592. /* Move partition element back to middle */
  593. ExchangeSpans(0, j);
  594. /* Recurse */
  595. if (numSpans-j-1 > 1)
  596. miQuickSortSpansX (&points[j+1], &widths[j+1], numSpans-j-1);
  597. numSpans = j;
  598. } while (numSpans > 1);
  599. }
  600. /* Sort an unordered list of spans by y, so that it becomes a Spans. */
  601. void
  602. miQuickSortSpansY (miPoint *points, unsigned int *widths, int numSpans)
  603. {
  604. int y;
  605. int i, j, m;
  606. miPoint *r;
  607. if (numSpans <= 1) /* nothing to do */
  608. return;
  609. #define ExchangeSpans(a, b) \
  610. { \
  611. miPoint tpt; \
  612. unsigned int tw; \
  613. \
  614. tpt = points[a]; points[a] = points[b]; points[b] = tpt; \
  615. tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
  616. }
  617. do
  618. {
  619. if (numSpans < 9)
  620. /* do insertion sort */
  621. {
  622. int yprev;
  623. yprev = points[0].y;
  624. i = 1;
  625. do /* while i != numSpans */
  626. {
  627. y = points[i].y;
  628. if (yprev > y)
  629. {
  630. /* points[i] is out of order. Move into proper location. */
  631. miPoint tpt;
  632. unsigned int tw;
  633. int k;
  634. for (j = 0; y >= points[j].y; j++)
  635. {
  636. }
  637. tpt = points[i];
  638. tw = widths[i];
  639. for (k = i; k != j; k--)
  640. {
  641. points[k] = points[k-1];
  642. widths[k] = widths[k-1];
  643. }
  644. points[j] = tpt;
  645. widths[j] = tw;
  646. y = points[i].y;
  647. } /* if out of order */
  648. yprev = y;
  649. i++;
  650. } while (i != numSpans);
  651. /* end of insertion sort */
  652. return;
  653. }
  654. /* Choose partition element, stick in location 0 */
  655. m = numSpans / 2;
  656. if (points[m].y > points[0].y)
  657. ExchangeSpans(m, 0);
  658. if (points[m].y > points[numSpans-1].y)
  659. ExchangeSpans(m, numSpans-1);
  660. if (points[m].y > points[0].y)
  661. ExchangeSpans(m, 0);
  662. y = points[0].y;
  663. /* Partition array */
  664. i = 0;
  665. j = numSpans;
  666. do
  667. {
  668. r = &(points[i]);
  669. do
  670. {
  671. r++;
  672. i++;
  673. }
  674. while (i != numSpans && r->y < y)
  675. ;
  676. r = &(points[j]);
  677. do
  678. {
  679. r--;
  680. j--;
  681. }
  682. while (y < r->y);
  683. if (i < j) ExchangeSpans(i, j);
  684. }
  685. while (i < j);
  686. /* Move partition element back to middle */
  687. ExchangeSpans(0, j);
  688. /* Recurse */
  689. if (numSpans-j-1 > 1)
  690. miQuickSortSpansY (&points[j+1], &widths[j+1], numSpans-j-1);
  691. numSpans = j;
  692. } while (numSpans > 1);
  693. }
  694. /* Uniquify the spans in a Spans. (Spans at each y value are assumed to
  695. have been sorted on x, perhaps by calling miQuickSortSpansX() above.)
  696. Also, create a new Spans: stash the uniquified spans into the previously
  697. allocated arrays newPoints and newWidths. Returns the number of unique
  698. spans. Called only if numSpans > 1. */
  699. static int
  700. miUniquifySpansX (const Spans *spans, miPoint *newPoints, unsigned int *newWidths)
  701. {
  702. int newx1, newx2, oldpt, i, y;
  703. miPoint *oldPoints;
  704. unsigned int *oldWidths, *startNewWidths;
  705. startNewWidths = newWidths;
  706. oldPoints = spans->points;
  707. oldWidths = spans->widths;
  708. y = oldPoints->y;
  709. newx1 = oldPoints->x;
  710. newx2 = newx1 + (int)(*oldWidths);
  711. for (i = spans->count - 1; i > 0; i--)
  712. {
  713. oldPoints++;
  714. oldWidths++;
  715. oldpt = oldPoints->x;
  716. if (oldpt > newx2)
  717. {
  718. /* write current span, start a new one */
  719. newPoints->x = newx1;
  720. newPoints->y = y;
  721. *newWidths = (unsigned int)(newx2 - newx1);
  722. newPoints++;
  723. newWidths++;
  724. newx1 = oldpt;
  725. newx2 = oldpt + (int)(*oldWidths);
  726. }
  727. else
  728. {
  729. /* extend current span, if old extends beyond new */
  730. oldpt = oldpt + (int)(*oldWidths);
  731. if (oldpt > newx2)
  732. newx2 = oldpt;
  733. }
  734. }
  735. /* write final span */
  736. newPoints->x = newx1;
  737. *newWidths = (unsigned int)(newx2 - newx1);
  738. newPoints->y = y;
  739. return (int)((newWidths - startNewWidths) + 1);
  740. }