/* * Convert cubic Bezier curve control points to polyline * vertices. Leaves the last vertex off, so you can continue * with another curve. */ static void bpts1(Plist *l, Point p0, Point p1, Point p2, Point p3, int scale) { Point p01, p12, p23, p012, p123, p0123; Point tp0, tp1, tp2, tp3; tp0=divpt(p0, scale); tp1=divpt(p1, scale); tp2=divpt(p2, scale); tp3=divpt(p3, scale); if(psdist(tp1, tp0, tp3)<=1 && psdist(tp2, tp0, tp3)<=1){ appendpt(l, tp0); appendpt(l, tp1); appendpt(l, tp2); } else{ /* * if scale factor is getting too big for comfort, * rescale now & concede the rounding error */ if(scale>(1<<12)){ p0=tp0; p1=tp1; p2=tp2; p3=tp3; scale=1; } p01=addpt(p0, p1); p12=addpt(p1, p2); p23=addpt(p2, p3); p012=addpt(p01, p12); p123=addpt(p12, p23); p0123=addpt(p012, p123); bpts1(l, mulpt(p0, 8), mulpt(p01, 4), mulpt(p012, 2), p0123, scale*8); bpts1(l, p0123, mulpt(p123, 2), mulpt(p23, 4), mulpt(p3, 8), scale*8); } }
static void _bezsplinepts(Plist *l, Point *pt, int npt) { Point *p, *ep; Point a, b, c, d; int periodic; if(npt<3) return; ep = &pt[npt-3]; periodic = eqpt(pt[0], ep[2]); if(periodic){ a = divpt(addpt(ep[1], pt[0]), 2); b = divpt(addpt(ep[1], mulpt(pt[0], 5)), 6); c = divpt(addpt(mulpt(pt[0], 5), pt[1]), 6); d = divpt(addpt(pt[0], pt[1]), 2); bpts(l, a, b, c, d); } for(p=pt; p<=ep; p++){ if(p==pt && !periodic){ a = p[0]; b = divpt(addpt(p[0], mulpt(p[1], 2)), 3); } else{ a = divpt(addpt(p[0], p[1]), 2); b = divpt(addpt(p[0], mulpt(p[1], 5)), 6); } if(p==ep && !periodic){ c = divpt(addpt(mulpt(p[1], 2), p[2]), 3); d = p[2]; } else{ c = divpt(addpt(mulpt(p[1], 5), p[2]), 6); d = divpt(addpt(p[1], p[2]), 2); } bpts(l, a, b, c, d); } appendpt(l, d); }
static void bezierpts(Plist *l, Point p0, Point p1, Point p2, Point p3) { bpts(l, p0, p1, p2, p3); appendpt(l, p3); }
/* append: */ static int append(path * path, int bi, point p0, point p1, int polysz) { point v[8]; /* worst case 4 corners + 2 segs * 2 points each */ point w[8]; box b = path->boxes[bi]; box bb; int i, i0, npw, delta; point q0 = { 0, 0 }, q1 = { 0, 0}, r; int pn; /* v = 4 corners of b, p0 and p1 */ pn = 0; v[pn++] = b.LL; v[pn++] = mkpt(b.UR.x, b.LL.y); v[pn++] = b.UR; v[pn++] = mkpt(b.LL.x, b.UR.y); v[pn++] = p0; v[pn++] = p1; if (bi + 1 < path->nbox) { bb = path->boxes[bi + 1]; /* determine points q0,q1 where b and bb touch and append to v */ if (b.UR.x == bb.LL.x) { q0.x = q1.x = b.UR.x; q0.y = MIN(b.UR.y, bb.UR.y); q1.y = MAX(b.LL.y, bb.LL.y); } else if (b.LL.x == bb.UR.x) { q0.x = q1.x = b.LL.x; q0.y = MIN(b.UR.y, bb.UR.y); q1.y = MAX(b.LL.y, bb.LL.y); } else if (b.UR.y == bb.LL.y) { q0.y = q1.y = b.UR.y; q0.x = MIN(b.UR.x, bb.UR.x); q1.x = MAX(b.LL.x, bb.LL.x); } else if (b.LL.y == bb.UR.y) { q0.y = q1.y = b.LL.y; q0.x = MIN(b.UR.x, bb.UR.x); q1.x = MAX(b.LL.x, bb.LL.x); } else abort(); v[pn++] = q0; v[pn++] = q1; } /* sort v so that the cyclic order is p0, all other points, p1 */ B = b; qsort(v, pn, sizeof(v[0]), cmpf); /* eliminate duplicates and record i0 = index of p0 in w */ w[0] = v[0]; npw = 1; i0 = -1; for (i = 0; i < pn; i++) { if (pteq(w[npw - 1], p0)) i0 = npw - 1; if (!pteq(v[i], w[npw - 1])) w[npw++] = v[i]; } i = i0; if (bi == 0) polysz = appendpt(p0, polysz); if (pteq(p1, w[(i0 + 1) % npw])) delta = -1; else if (pteq(p1, w[(i0 - 1 + npw) % npw])) delta = 1; else abort(); do { i = (i + delta + npw) % npw; /* go to the next point in order */ r = w[i]; /* call it r */ /* append r to current poly, except p0 and p1 are special cases */ if ((bi == 0) || (!pteq(r, p0) && !pteq(r, p1))) polysz = appendpt(r, polysz); if (pteq(r, p1)) break; if (bi + 1 < path->nbox) { /* recur when we hit the next box */ if (pteq(r, q0)) { polysz = append(path, bi + 1, q0, q1, polysz); polysz = appendpt(q1, polysz); /* assumes q1 != p0 and p1 */ i += delta; /* skip q1 */ } else if (pteq(r, q1)) { polysz = append(path, bi + 1, q1, q0, polysz); polysz = appendpt(q0, polysz); i += delta; } } } while (i != i0); return polysz; }