17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier
57dd7cddfSDavid du Colombier #define PINC 32 /* realloc granularity */
67dd7cddfSDavid du Colombier
77dd7cddfSDavid du Colombier typedef struct Plist Plist;
87dd7cddfSDavid du Colombier struct Plist
97dd7cddfSDavid du Colombier {
107dd7cddfSDavid du Colombier Point *p;
117dd7cddfSDavid du Colombier int np; /* -1 if malloc/realloc failed */
127dd7cddfSDavid du Colombier };
137dd7cddfSDavid du Colombier
147dd7cddfSDavid du Colombier static void
appendpt(Plist * l,Point p)157dd7cddfSDavid du Colombier appendpt(Plist *l, Point p)
167dd7cddfSDavid du Colombier {
177dd7cddfSDavid du Colombier if(l->np == -1)
187dd7cddfSDavid du Colombier return;
197dd7cddfSDavid du Colombier if(l->np == 0)
207dd7cddfSDavid du Colombier l->p = malloc(PINC*sizeof(Point));
217dd7cddfSDavid du Colombier else if(l->np%PINC == 0)
227dd7cddfSDavid du Colombier l->p = realloc(l->p, (l->np+PINC)*sizeof(Point));
237dd7cddfSDavid du Colombier if(l->p == 0){
247dd7cddfSDavid du Colombier l->np = -1;
257dd7cddfSDavid du Colombier return;
267dd7cddfSDavid du Colombier }
277dd7cddfSDavid du Colombier l->p[l->np++] = p;
287dd7cddfSDavid du Colombier }
297dd7cddfSDavid du Colombier
307dd7cddfSDavid du Colombier static int
normsq(Point p)317dd7cddfSDavid du Colombier normsq(Point p)
327dd7cddfSDavid du Colombier {
337dd7cddfSDavid du Colombier return p.x*p.x+p.y*p.y;
347dd7cddfSDavid du Colombier }
357dd7cddfSDavid du Colombier
367dd7cddfSDavid du Colombier static int
psdist(Point p,Point a,Point b)377dd7cddfSDavid du Colombier psdist(Point p, Point a, Point b)
387dd7cddfSDavid du Colombier {
397dd7cddfSDavid du Colombier int num, den;
407dd7cddfSDavid du Colombier
417dd7cddfSDavid du Colombier p = subpt(p, a);
427dd7cddfSDavid du Colombier b = subpt(b, a);
437dd7cddfSDavid du Colombier num = p.x*b.x + p.y*b.y;
447dd7cddfSDavid du Colombier if(num <= 0)
457dd7cddfSDavid du Colombier return normsq(p);
467dd7cddfSDavid du Colombier den = normsq(b);
477dd7cddfSDavid du Colombier if(num >= den)
487dd7cddfSDavid du Colombier return normsq(subpt(b, p));
497dd7cddfSDavid du Colombier return normsq(subpt(divpt(mulpt(b, num), den), p));
507dd7cddfSDavid du Colombier }
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier /*
537dd7cddfSDavid du Colombier * Convert cubic Bezier curve control points to polyline
547dd7cddfSDavid du Colombier * vertices. Leaves the last vertex off, so you can continue
557dd7cddfSDavid du Colombier * with another curve.
567dd7cddfSDavid du Colombier */
577dd7cddfSDavid du Colombier static void
bpts1(Plist * l,Point p0,Point p1,Point p2,Point p3,int scale)587dd7cddfSDavid du Colombier bpts1(Plist *l, Point p0, Point p1, Point p2, Point p3, int scale)
597dd7cddfSDavid du Colombier {
607dd7cddfSDavid du Colombier Point p01, p12, p23, p012, p123, p0123;
617dd7cddfSDavid du Colombier Point tp0, tp1, tp2, tp3;
627dd7cddfSDavid du Colombier tp0=divpt(p0, scale);
637dd7cddfSDavid du Colombier tp1=divpt(p1, scale);
647dd7cddfSDavid du Colombier tp2=divpt(p2, scale);
657dd7cddfSDavid du Colombier tp3=divpt(p3, scale);
667dd7cddfSDavid du Colombier if(psdist(tp1, tp0, tp3)<=1 && psdist(tp2, tp0, tp3)<=1){
677dd7cddfSDavid du Colombier appendpt(l, tp0);
687dd7cddfSDavid du Colombier appendpt(l, tp1);
697dd7cddfSDavid du Colombier appendpt(l, tp2);
707dd7cddfSDavid du Colombier }
717dd7cddfSDavid du Colombier else{
727dd7cddfSDavid du Colombier /*
737dd7cddfSDavid du Colombier * if scale factor is getting too big for comfort,
747dd7cddfSDavid du Colombier * rescale now & concede the rounding error
757dd7cddfSDavid du Colombier */
767dd7cddfSDavid du Colombier if(scale>(1<<12)){
777dd7cddfSDavid du Colombier p0=tp0;
787dd7cddfSDavid du Colombier p1=tp1;
797dd7cddfSDavid du Colombier p2=tp2;
807dd7cddfSDavid du Colombier p3=tp3;
817dd7cddfSDavid du Colombier scale=1;
827dd7cddfSDavid du Colombier }
837dd7cddfSDavid du Colombier p01=addpt(p0, p1);
847dd7cddfSDavid du Colombier p12=addpt(p1, p2);
857dd7cddfSDavid du Colombier p23=addpt(p2, p3);
867dd7cddfSDavid du Colombier p012=addpt(p01, p12);
877dd7cddfSDavid du Colombier p123=addpt(p12, p23);
887dd7cddfSDavid du Colombier p0123=addpt(p012, p123);
897dd7cddfSDavid du Colombier bpts1(l, mulpt(p0, 8), mulpt(p01, 4), mulpt(p012, 2), p0123, scale*8);
907dd7cddfSDavid du Colombier bpts1(l, p0123, mulpt(p123, 2), mulpt(p23, 4), mulpt(p3, 8), scale*8);
917dd7cddfSDavid du Colombier }
927dd7cddfSDavid du Colombier }
937dd7cddfSDavid du Colombier
947dd7cddfSDavid du Colombier static void
bpts(Plist * l,Point p0,Point p1,Point p2,Point p3)957dd7cddfSDavid du Colombier bpts(Plist *l, Point p0, Point p1, Point p2, Point p3)
967dd7cddfSDavid du Colombier {
977dd7cddfSDavid du Colombier bpts1(l, p0, p1, p2, p3, 1);
987dd7cddfSDavid du Colombier }
997dd7cddfSDavid du Colombier
1007dd7cddfSDavid du Colombier static void
bezierpts(Plist * l,Point p0,Point p1,Point p2,Point p3)1017dd7cddfSDavid du Colombier bezierpts(Plist *l, Point p0, Point p1, Point p2, Point p3)
1027dd7cddfSDavid du Colombier {
1037dd7cddfSDavid du Colombier bpts(l, p0, p1, p2, p3);
1047dd7cddfSDavid du Colombier appendpt(l, p3);
1057dd7cddfSDavid du Colombier }
1067dd7cddfSDavid du Colombier
1077dd7cddfSDavid du Colombier static void
_bezsplinepts(Plist * l,Point * pt,int npt)108*ac57dd0bSDavid du Colombier _bezsplinepts(Plist *l, Point *pt, int npt)
1097dd7cddfSDavid du Colombier {
1107dd7cddfSDavid du Colombier Point *p, *ep;
1117dd7cddfSDavid du Colombier Point a, b, c, d;
1127dd7cddfSDavid du Colombier int periodic;
1137dd7cddfSDavid du Colombier
1147dd7cddfSDavid du Colombier if(npt<3)
1157dd7cddfSDavid du Colombier return;
1167dd7cddfSDavid du Colombier ep = &pt[npt-3];
1177dd7cddfSDavid du Colombier periodic = eqpt(pt[0], ep[2]);
1187dd7cddfSDavid du Colombier if(periodic){
1197dd7cddfSDavid du Colombier a = divpt(addpt(ep[1], pt[0]), 2);
1207dd7cddfSDavid du Colombier b = divpt(addpt(ep[1], mulpt(pt[0], 5)), 6);
1217dd7cddfSDavid du Colombier c = divpt(addpt(mulpt(pt[0], 5), pt[1]), 6);
1227dd7cddfSDavid du Colombier d = divpt(addpt(pt[0], pt[1]), 2);
1237dd7cddfSDavid du Colombier bpts(l, a, b, c, d);
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier for(p=pt; p<=ep; p++){
1267dd7cddfSDavid du Colombier if(p==pt && !periodic){
1277dd7cddfSDavid du Colombier a = p[0];
1287dd7cddfSDavid du Colombier b = divpt(addpt(p[0], mulpt(p[1], 2)), 3);
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier else{
1317dd7cddfSDavid du Colombier a = divpt(addpt(p[0], p[1]), 2);
1327dd7cddfSDavid du Colombier b = divpt(addpt(p[0], mulpt(p[1], 5)), 6);
1337dd7cddfSDavid du Colombier }
1347dd7cddfSDavid du Colombier if(p==ep && !periodic){
1357dd7cddfSDavid du Colombier c = divpt(addpt(mulpt(p[1], 2), p[2]), 3);
1367dd7cddfSDavid du Colombier d = p[2];
1377dd7cddfSDavid du Colombier }
1387dd7cddfSDavid du Colombier else{
1397dd7cddfSDavid du Colombier c = divpt(addpt(mulpt(p[1], 5), p[2]), 6);
1407dd7cddfSDavid du Colombier d = divpt(addpt(p[1], p[2]), 2);
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier bpts(l, a, b, c, d);
1437dd7cddfSDavid du Colombier }
1447dd7cddfSDavid du Colombier appendpt(l, d);
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier
1477dd7cddfSDavid du Colombier int
bezsplinepts(Point * pt,int npt,Point ** pp)148*ac57dd0bSDavid du Colombier bezsplinepts(Point *pt, int npt, Point **pp)
149*ac57dd0bSDavid du Colombier {
150*ac57dd0bSDavid du Colombier Plist l;
151*ac57dd0bSDavid du Colombier l.np = 0;
152*ac57dd0bSDavid du Colombier l.p = nil;
153*ac57dd0bSDavid du Colombier _bezsplinepts(&l, pt, npt);
154*ac57dd0bSDavid du Colombier *pp = l.p;
155*ac57dd0bSDavid du Colombier return l.np;
156*ac57dd0bSDavid du Colombier }
157*ac57dd0bSDavid du Colombier
158*ac57dd0bSDavid du Colombier int
bezier(Image * dst,Point p0,Point p1,Point p2,Point p3,int end0,int end1,int radius,Image * src,Point sp)1597dd7cddfSDavid du Colombier bezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp)
1607dd7cddfSDavid du Colombier {
161*ac57dd0bSDavid du Colombier return bezierop(dst, p0, p1, p2, p3, end0, end1, radius, src, sp, SoverD);
162*ac57dd0bSDavid du Colombier }
163*ac57dd0bSDavid du Colombier
164*ac57dd0bSDavid du Colombier int
bezierop(Image * dst,Point p0,Point p1,Point p2,Point p3,int end0,int end1,int radius,Image * src,Point sp,Drawop op)165*ac57dd0bSDavid du Colombier bezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
166*ac57dd0bSDavid du Colombier {
1677dd7cddfSDavid du Colombier Plist l;
1687dd7cddfSDavid du Colombier
1697dd7cddfSDavid du Colombier l.np = 0;
1707dd7cddfSDavid du Colombier bezierpts(&l, p0, p1, p2, p3);
1717dd7cddfSDavid du Colombier if(l.np == -1)
1727dd7cddfSDavid du Colombier return 0;
1737dd7cddfSDavid du Colombier if(l.np != 0){
174*ac57dd0bSDavid du Colombier polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, p0), l.p[0]), op);
1757dd7cddfSDavid du Colombier free(l.p);
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier return 1;
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier
1807dd7cddfSDavid du Colombier int
bezspline(Image * dst,Point * pt,int npt,int end0,int end1,int radius,Image * src,Point sp)1817dd7cddfSDavid du Colombier bezspline(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp)
1827dd7cddfSDavid du Colombier {
183*ac57dd0bSDavid du Colombier return bezsplineop(dst, pt, npt, end0, end1, radius, src, sp, SoverD);
184*ac57dd0bSDavid du Colombier }
185*ac57dd0bSDavid du Colombier
186*ac57dd0bSDavid du Colombier int
bezsplineop(Image * dst,Point * pt,int npt,int end0,int end1,int radius,Image * src,Point sp,Drawop op)187*ac57dd0bSDavid du Colombier bezsplineop(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
188*ac57dd0bSDavid du Colombier {
1897dd7cddfSDavid du Colombier Plist l;
1907dd7cddfSDavid du Colombier
1917dd7cddfSDavid du Colombier l.np = 0;
192*ac57dd0bSDavid du Colombier _bezsplinepts(&l, pt, npt);
1937dd7cddfSDavid du Colombier if(l.np==-1)
1947dd7cddfSDavid du Colombier return 0;
1957dd7cddfSDavid du Colombier if(l.np != 0){
196*ac57dd0bSDavid du Colombier polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, pt[0]), l.p[0]), op);
1977dd7cddfSDavid du Colombier free(l.p);
1987dd7cddfSDavid du Colombier }
1997dd7cddfSDavid du Colombier return 1;
2007dd7cddfSDavid du Colombier }
2017dd7cddfSDavid du Colombier
2027dd7cddfSDavid du Colombier int
fillbezier(Image * dst,Point p0,Point p1,Point p2,Point p3,int w,Image * src,Point sp)2037dd7cddfSDavid du Colombier fillbezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp)
2047dd7cddfSDavid du Colombier {
205*ac57dd0bSDavid du Colombier return fillbezierop(dst, p0, p1, p2, p3, w, src, sp, SoverD);
206*ac57dd0bSDavid du Colombier }
207*ac57dd0bSDavid du Colombier
208*ac57dd0bSDavid du Colombier int
fillbezierop(Image * dst,Point p0,Point p1,Point p2,Point p3,int w,Image * src,Point sp,Drawop op)209*ac57dd0bSDavid du Colombier fillbezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp, Drawop op)
210*ac57dd0bSDavid du Colombier {
2117dd7cddfSDavid du Colombier Plist l;
2127dd7cddfSDavid du Colombier
2137dd7cddfSDavid du Colombier l.np = 0;
2147dd7cddfSDavid du Colombier bezierpts(&l, p0, p1, p2, p3);
2157dd7cddfSDavid du Colombier if(l.np == -1)
2167dd7cddfSDavid du Colombier return 0;
2177dd7cddfSDavid du Colombier if(l.np != 0){
218*ac57dd0bSDavid du Colombier fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, p0), l.p[0]), op);
2197dd7cddfSDavid du Colombier free(l.p);
2207dd7cddfSDavid du Colombier }
2217dd7cddfSDavid du Colombier return 1;
2227dd7cddfSDavid du Colombier }
2237dd7cddfSDavid du Colombier
2247dd7cddfSDavid du Colombier int
fillbezspline(Image * dst,Point * pt,int npt,int w,Image * src,Point sp)2257dd7cddfSDavid du Colombier fillbezspline(Image *dst, Point *pt, int npt, int w, Image *src, Point sp)
2267dd7cddfSDavid du Colombier {
227*ac57dd0bSDavid du Colombier return fillbezsplineop(dst, pt, npt, w, src, sp, SoverD);
228*ac57dd0bSDavid du Colombier }
229*ac57dd0bSDavid du Colombier
230*ac57dd0bSDavid du Colombier int
fillbezsplineop(Image * dst,Point * pt,int npt,int w,Image * src,Point sp,Drawop op)231*ac57dd0bSDavid du Colombier fillbezsplineop(Image *dst, Point *pt, int npt, int w, Image *src, Point sp, Drawop op)
232*ac57dd0bSDavid du Colombier {
2337dd7cddfSDavid du Colombier Plist l;
2347dd7cddfSDavid du Colombier
2357dd7cddfSDavid du Colombier l.np = 0;
236*ac57dd0bSDavid du Colombier _bezsplinepts(&l, pt, npt);
2377dd7cddfSDavid du Colombier if(l.np == -1)
2387dd7cddfSDavid du Colombier return 0;
2397dd7cddfSDavid du Colombier if(l.np > 0){
240*ac57dd0bSDavid du Colombier fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, pt[0]), l.p[0]), op);
2417dd7cddfSDavid du Colombier free(l.p);
2427dd7cddfSDavid du Colombier }
2437dd7cddfSDavid du Colombier return 1;
2447dd7cddfSDavid du Colombier }
245