bezier.c 4.8 KB

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