bezier.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <draw.h>
  12. #define PINC 32 /* realloc granularity */
  13. typedef struct Plist Plist;
  14. struct Plist
  15. {
  16. Point *p;
  17. int np; /* -1 if malloc/realloc failed */
  18. };
  19. static void
  20. appendpt(Plist *l, Point p)
  21. {
  22. if(l->np == -1)
  23. return;
  24. if(l->np == 0)
  25. l->p = malloc(PINC*sizeof(Point));
  26. else if(l->np%PINC == 0)
  27. l->p = realloc(l->p, (l->np+PINC)*sizeof(Point));
  28. if(l->p == 0){
  29. l->np = -1;
  30. return;
  31. }
  32. l->p[l->np++] = p;
  33. }
  34. static int
  35. normsq(Point p)
  36. {
  37. return p.x*p.x+p.y*p.y;
  38. }
  39. static int
  40. psdist(Point p, Point a, Point b)
  41. {
  42. int num, den;
  43. p = subpt(p, a);
  44. b = subpt(b, a);
  45. num = p.x*b.x + p.y*b.y;
  46. if(num <= 0)
  47. return normsq(p);
  48. den = normsq(b);
  49. if(num >= den)
  50. return normsq(subpt(b, p));
  51. return normsq(subpt(divpt(mulpt(b, num), den), p));
  52. }
  53. /*
  54. * Convert cubic Bezier curve control points to polyline
  55. * vertices. Leaves the last vertex off, so you can continue
  56. * with another curve.
  57. */
  58. static void
  59. bpts1(Plist *l, Point p0, Point p1, Point p2, Point p3, int scale)
  60. {
  61. Point p01, p12, p23, p012, p123, p0123;
  62. Point tp0, tp1, tp2, tp3;
  63. tp0=divpt(p0, scale);
  64. tp1=divpt(p1, scale);
  65. tp2=divpt(p2, scale);
  66. tp3=divpt(p3, scale);
  67. if(psdist(tp1, tp0, tp3)<=1 && psdist(tp2, tp0, tp3)<=1){
  68. appendpt(l, tp0);
  69. appendpt(l, tp1);
  70. appendpt(l, tp2);
  71. }
  72. else{
  73. /*
  74. * if scale factor is getting too big for comfort,
  75. * rescale now & concede the rounding error
  76. */
  77. if(scale>(1<<12)){
  78. p0=tp0;
  79. p1=tp1;
  80. p2=tp2;
  81. p3=tp3;
  82. scale=1;
  83. }
  84. p01=addpt(p0, p1);
  85. p12=addpt(p1, p2);
  86. p23=addpt(p2, p3);
  87. p012=addpt(p01, p12);
  88. p123=addpt(p12, p23);
  89. p0123=addpt(p012, p123);
  90. bpts1(l, mulpt(p0, 8), mulpt(p01, 4), mulpt(p012, 2), p0123, scale*8);
  91. bpts1(l, p0123, mulpt(p123, 2), mulpt(p23, 4), mulpt(p3, 8), scale*8);
  92. }
  93. }
  94. static void
  95. bpts(Plist *l, Point p0, Point p1, Point p2, Point p3)
  96. {
  97. bpts1(l, p0, p1, p2, p3, 1);
  98. }
  99. static void
  100. bezierpts(Plist *l, Point p0, Point p1, Point p2, Point p3)
  101. {
  102. bpts(l, p0, p1, p2, p3);
  103. appendpt(l, p3);
  104. }
  105. static void
  106. _bezsplinepts(Plist *l, Point *pt, int npt)
  107. {
  108. Point *p, *ep;
  109. Point a, b, c, d;
  110. int periodic;
  111. if(npt<3)
  112. return;
  113. ep = &pt[npt-3];
  114. periodic = eqpt(pt[0], ep[2]);
  115. if(periodic){
  116. a = divpt(addpt(ep[1], pt[0]), 2);
  117. b = divpt(addpt(ep[1], mulpt(pt[0], 5)), 6);
  118. c = divpt(addpt(mulpt(pt[0], 5), pt[1]), 6);
  119. d = divpt(addpt(pt[0], pt[1]), 2);
  120. bpts(l, a, b, c, d);
  121. }
  122. for(p=pt; p<=ep; p++){
  123. if(p==pt && !periodic){
  124. a = p[0];
  125. b = divpt(addpt(p[0], mulpt(p[1], 2)), 3);
  126. }
  127. else{
  128. a = divpt(addpt(p[0], p[1]), 2);
  129. b = divpt(addpt(p[0], mulpt(p[1], 5)), 6);
  130. }
  131. if(p==ep && !periodic){
  132. c = divpt(addpt(mulpt(p[1], 2), p[2]), 3);
  133. d = p[2];
  134. }
  135. else{
  136. c = divpt(addpt(mulpt(p[1], 5), p[2]), 6);
  137. d = divpt(addpt(p[1], p[2]), 2);
  138. }
  139. bpts(l, a, b, c, d);
  140. }
  141. appendpt(l, d);
  142. }
  143. int
  144. bezsplinepts(Point *pt, int npt, Point **pp)
  145. {
  146. Plist l;
  147. l.np = 0;
  148. l.p = nil;
  149. _bezsplinepts(&l, pt, npt);
  150. *pp = l.p;
  151. return l.np;
  152. }
  153. int
  154. bezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp)
  155. {
  156. return bezierop(dst, p0, p1, p2, p3, end0, end1, radius, src, sp, SoverD);
  157. }
  158. int
  159. bezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
  160. {
  161. Plist l;
  162. l.np = 0;
  163. bezierpts(&l, p0, p1, p2, p3);
  164. if(l.np == -1)
  165. return 0;
  166. if(l.np != 0){
  167. polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, p0), l.p[0]), op);
  168. free(l.p);
  169. }
  170. return 1;
  171. }
  172. int
  173. bezspline(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp)
  174. {
  175. return bezsplineop(dst, pt, npt, end0, end1, radius, src, sp, SoverD);
  176. }
  177. int
  178. bezsplineop(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
  179. {
  180. Plist l;
  181. l.np = 0;
  182. _bezsplinepts(&l, pt, npt);
  183. if(l.np==-1)
  184. return 0;
  185. if(l.np != 0){
  186. polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, pt[0]), l.p[0]), op);
  187. free(l.p);
  188. }
  189. return 1;
  190. }
  191. int
  192. fillbezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp)
  193. {
  194. return fillbezierop(dst, p0, p1, p2, p3, w, src, sp, SoverD);
  195. }
  196. int
  197. fillbezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp, Drawop op)
  198. {
  199. Plist l;
  200. l.np = 0;
  201. bezierpts(&l, p0, p1, p2, p3);
  202. if(l.np == -1)
  203. return 0;
  204. if(l.np != 0){
  205. fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, p0), l.p[0]), op);
  206. free(l.p);
  207. }
  208. return 1;
  209. }
  210. int
  211. fillbezspline(Image *dst, Point *pt, int npt, int w, Image *src, Point sp)
  212. {
  213. return fillbezsplineop(dst, pt, npt, w, src, sp, SoverD);
  214. }
  215. int
  216. fillbezsplineop(Image *dst, Point *pt, int npt, int w, Image *src, Point sp, Drawop op)
  217. {
  218. Plist l;
  219. l.np = 0;
  220. _bezsplinepts(&l, pt, npt);
  221. if(l.np == -1)
  222. return 0;
  223. if(l.np > 0){
  224. fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, pt[0]), l.p[0]), op);
  225. free(l.p);
  226. }
  227. return 1;
  228. }