bezier.c 4.8 KB

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