Plan 9 from Bell Labs’s /usr/web/sources/extra/art/bezier.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
 * Routines to mangle Bezier curves (of some fixed order)
 *	bsplit(b, l, r)			split a bezier curve at its midpoint
 *	Rectangle bboxbezier(b)		bounding box of a bezier curve
 *	Dpoint nearbezier(b, p, LEVEL)	return the nearest point to the given bezier curve
 *	inboxbezier(b, box, LEVEL)	does the bezier curve intersect the box?
 *	drawbezier(b, color, Image)	draw a bezier curve in a bitmap
 */
#include "art.h"

Image *color;

Flt min(Flt a, Flt b){ return a<b?a:b; }
Flt max(Flt a, Flt b){ return a>b?a:b; }
Flt dsq(Dpoint p, Dpoint q){
	p.x-=q.x;
	p.y-=q.y;
	return p.x*p.x+p.y*p.y;
}
void bsplit(Bezier b, Bezier l, Bezier r){
	Dpoint subd[ORDER][ORDER];
	int i, j;
	Dpoint *p, *q, *ep;
	ep=&subd[0][ORDER];
	for(p=&subd[0][0],q=b;p!=ep;p++, q++) *p=*q;
	for(i=1;i!=ORDER;i++){
		ep=&subd[i][ORDER-i];
		for(p=&subd[i][0],q=&subd[i-1][0];p!=ep;p++, q++)
			*p=dmidpt(q[0], q[1]);
	}
	ep=&l[ORDER];
	for(p=l,q=&subd[0][0];p!=ep;p++,q+=ORDER) *p=*q;
	ep=&r[ORDER];
	for(p=r,q=&subd[ORDER-1][0];p!=ep;p++,q+=1-ORDER) *p=*q;
}
Dpoint closevert(Bezier b, Dpoint testp){
	Flt d, mind;
	Dpoint close, p, *bp, *ebp=b+ORDER-1;
	close=b[0];
	mind=dsq(close, testp);
	for(bp=b;bp!=ebp;bp++){
		p=nearseg(bp[0], bp[1], testp);
		d=dsq(p, testp);
		if(d<mind){
			mind=d;
			close=p;
		}
	}
	return close;
}
Drectangle bboxbezier(Bezier b){
	int i;
	Drectangle box;
	Dpoint *bp, *ebp=b+ORDER;
	box.min=b[0];
	box.max=b[0];
	for(bp=b+1;bp!=ebp;bp++){
		if(bp->x<box.min.x) box.min.x=bp->x;
		if(bp->x>box.max.x) box.max.x=bp->x;
		if(bp->y<box.min.y) box.min.y=bp->y;
		if(bp->y>box.max.y) box.max.y=bp->y;
	}
	return box;
}
/*
 * If close is closer to p than any point on b, return close.
 * Otherwise, return the closest point to p on b.
 */
Dpoint nearbezier(Bezier b, Dpoint p, Dpoint close, int level){
	Drectangle bbox;
	Bezier l, r;
	Dpoint d;
	bbox=bboxbezier(b);
	d.x=p.x<bbox.min.x?bbox.min.x:p.x<=bbox.max.x?p.x:bbox.max.x;
	d.y=p.y<bbox.min.y?bbox.min.y:p.y<=bbox.max.y?p.y:bbox.max.y;
	if(dsq(p, d)>dsq(p, close)) return close;
	if(level==0) return closevert(b, p);
	bsplit(b, l, r);
	return nearbezier(r, p, nearbezier(l, p, close, level-1), level-1);
}
int inboxbezier(Bezier b, Drectangle box, int level){
	Drectangle bound;
	Bezier l, r;
	bound=bboxbezier(b);
	if(bound.max.x<box.min.x || box.max.x<bound.min.x
	|| bound.max.y<box.min.y || box.max.y<bound.min.y) return 0;
	if(box.min.x<=bound.min.x && bound.max.x<=box.max.x
	&& box.min.y<=bound.min.y && bound.max.y<=box.max.y) return 1;
	if(level==0) return 1;
	bsplit(b, l, r);
	return inboxbezier(l, box, level-1) || inboxbezier(r, box, level-1);
}
int seginterbezier(Dpoint p0, Dpoint p1, Bezier b, Dpoint *i, int level){
	Drectangle box;
	Bezier l, r;
	int n;
	if(level==0) return seginterseg(p0, p1, b[0], b[3], i);
	box=bboxbezier(b);
	if(p0.x<box.min.x && p1.x<box.min.x
	|| p0.x>box.max.x && p1.x>box.max.x
	|| p0.y<box.min.y && p1.y<box.min.y
	|| p0.y>box.max.y && p1.y>box.max.y) return 0;
	bsplit(b, l, r);
	n=seginterbezier(p0, p1, l, i, level-1);
	return n+seginterbezier(p0, p1, r, i+n, level-1);
}
int bezierinterbezier(Bezier b1, Bezier b2, Dpoint *i, int level){
	Drectangle box1, box2;
	Bezier l1, r1, l2, r2;
	int n;
	if(level==0) return seginterseg(b1[0], b1[3], b2[0], b2[3], i);
	box1=bboxbezier(b1);
	box2=bboxbezier(b2);
	if(!drectxrect(box1, box2)) return 0;
	bsplit(b1, l1, r1);
	bsplit(b2, l2, r2);
	n =bezierinterbezier(l1, l2, i, level-1);
	n+=bezierinterbezier(l1, r2, i+n, level-1);
	n+=bezierinterbezier(r1, r2, i+n, level-1);
	return n+bezierinterbezier(r1, l2, i+n, level-1);
}
int bstraight(Bezier b){
	int i;
	for(i=1;i!=ORDER-1;i++) if(pldist(b[i], b[0], b[ORDER-1])>.5/DPI) return 0;
	return 1;
}
void drawbezier(Bezier p, Image *b, Image *color){
	Bezier l, r;
	if(bstraight(p)){
		line(b, D2P(p[0]), D2P(p[ORDER-1]), Endsquare, Endsquare, 0, color, ZP);
		return;
	}
	bsplit(p, l, r);
	drawbezier(l, b, color);
	drawbezier(r, b, color);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.