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

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


/*
 * miscellaneous geometric functions
 * dadd(p,q)		a+b
 * dsub(p,q)		a-b
 * dlerp(p,d,a)		p+a*d
 * dlen(p)		sqrt(p.x^2 + p.y^2)
 * datan2(x,y)		atan2(x, y) in degrees
 * same(x,y)		fabs(x-y)<(.1 pixel)
 * deqpt(p,q)		same(p.x, q.x) && same(p.y, q.y)
 * D2P(p)		convert Dpoint (inch coords, y up) to Point (pixel coords, y down),
 *			mapping origin to lower left corner of screen window
 * P2D(p)		convert Point to Dpoint, inverse of D2P
 * dmul(p, a)		p*a
 * dreflect(p,q,r)	reflect p through line [q,r]
 * dmidpt(p,q)		(p+q)/2
 * circumcenter(p,q,r)	circumcenter of triangle pqr
 * triarea(p,q,r)	area of triangle pqr
 * circintercirc(c0,r0,c1,r1,i0,i1)
 *			store intersection points of circles (c0,r0) and (c1,r1) in *i0
 *			and *i1.  return the number of intersections.
 * segintercircle(p0,p1,cen,r,i0,i1)
 *			store intersections of line segment [p0,p1] and circle (cen,r) in
 *			*i0 and *i1.  return the number of intersections.
 * seginterseg(p0,p1,q0,q1,i)
 *			store intersection of segment [p0,p1] with [q0,q1] in *i.  return
 *			number of intersections  (0 or 1).
 * seginterarc(p0,p1,a0,a1,a2,i0,i1)
 *			store intersections of line segment [p0,p1] and arc (a0,a1,a2) in
 *			*i0 and *i1.  return the number of intersections.
 * dptinrect(p,r)	is point p in rectangle r?
 * drectxrect(r1,r2)	do rectangles r1 and r2 intersect?
 * drcanon(r)		make rectangle canonical (min.x<=max.x && min.y<=max.y)
 * pldist(p,q,r)	distance of point p from segment [q,r]
 * dunion(r, s)		smallest rectangle containing two rectangles
 */
#include "art.h"
Dpoint dadd(Dpoint p, Dpoint q){
	p.x+=q.x;
	p.y+=q.y;
	return p;
}
Dpoint dsub(Dpoint p, Dpoint q){
	p.x-=q.x;
	p.y-=q.y;
	return p;
}
Dpoint dlerp(Dpoint p, Dpoint dp, Flt alpha){
	p.x+=dp.x*alpha;
	p.y+=dp.y*alpha;
	return p;
}
Dpoint dcomb2(Dpoint p, Flt wp, Dpoint q, Flt wq){
	Flt den=wp+wq;
	p.x=(p.x*wp+q.x*wq)/den;
	p.y=(p.y*wp+q.y*wq)/den;
	return p;
}
Dpoint dcomb3(Dpoint p, Flt wp, Dpoint q, Flt wq, Dpoint r, Flt wr){
	Flt den=wp+wq+wr;
	p.x=(p.x*wp+q.x*wq+r.x*wr)/den;
	p.y=(p.y*wp+q.y*wq+r.y*wr)/den;
	return p;
}
Flt dlen(Dpoint p){
	return sqrt(p.x*p.x+p.y*p.y);
}
/*
 * arctangent in degrees
 */
Flt datan2(Flt x, Flt y){
	return degrees(atan2(x, y));
}
/*
 * the angle subtended by pq at the origin
 */
Flt angle(Dpoint p, Dpoint q){
	return datan2(p.x*q.y+p.y*q.x, p.x*q.x-p.y*q.y);
}
/*
 * absolute equality comparison
 */
int same(Flt a, Flt b){
	return fabs(a-b)<CLOSE;
}
int deqpt(Dpoint p, Dpoint q){
	return same(p.x, q.x) && same(p.y, q.y);
}
Point D2P(Dpoint d){
	Point p;
	p.x=(int)floor(d.x*DPI+.5)+dwgbox.min.x;
	p.y=dwgbox.max.y-1-(int)floor(d.y*DPI+.5);
	return p;
}
Dpoint P2D(Point p){
	Dpoint d;
	d.x=(p.x-dwgbox.min.x)/DPI;
	d.y=(dwgbox.max.y-1-p.y)/DPI;
	return d;
}
Dpoint dmul(Dpoint p, Flt m){
	p.x*=m;
	p.y*=m;
	return p;
}
Dpoint dreflect(Dpoint p, Dpoint p0, Dpoint p1){
	Dpoint a, b;
	a=dsub(p, p0);
	b=dsub(p1, p0);
	return dlerp(dsub(p0, a), b, 2*(a.x*b.x+a.y*b.y)/(b.x*b.x+b.y*b.y));
}
Dpoint dmidpt(Dpoint p, Dpoint q){
	p.x=(p.x+q.x)/2;
	p.y=(p.y+q.y)/2;
	return p;
}
/*
 * Return the circumcenter of triangle pqr
 */
Dpoint circumcenter(Dpoint p, Dpoint q, Dpoint r){
	Dpoint p0, d0, p1, d1, p10;
	Flt den;
	p0=dmidpt(p, q);
	p1=dmidpt(p, r);
	d0.x=q.y-p.y; d0.y=p.x-q.x;
	d1.x=r.y-p.y; d1.y=p.x-r.x;
	den=d1.x*d0.y-d0.x*d1.y;
	if(fabs(den)<SMALL) return p0;			/* parallel, punt */
	p10=dsub(p1, p0);
	return dlerp(p0, d0, (p10.y*d1.x-p10.x*d1.y)/den);
}
Flt triarea(Dpoint p0, Dpoint p1, Dpoint p2){
	return (p1.x-p0.x)*(p1.y+p0.y)+(p2.x-p1.x)*(p2.y+p1.y)+(p0.x-p2.x)*(p0.y+p2.y);
}
/*
 * Return the nearest point on segment p0:p1 to the test point
 */
Dpoint nearseg(Dpoint p0, Dpoint p1, Dpoint testp){
	Flt num, den;
	Dpoint q, r;
	q=dsub(p1, p0);
	r=dsub(testp, p0);
	num=q.x*r.x+q.y*r.y;
	if(num<=0) return p0;
	den=q.x*q.x+q.y*q.y;
	if(num>=den) return p1;
	return dlerp(p0, q, num/den);
}
/*
 * Compute intersections of circles centered at c[01] with
 * radii r[01].  Return number of intersections, store values
 * through i[01]
 */
int circintercirc(Dpoint c0, Flt r0, Dpoint c1, Flt r1, Dpoint *i){
	Flt r0sq=r0*r0, r1sq=r1*r1;
	Dpoint c10=dsub(c1, c0), p, d;
	Flt dsq=c10.x*c10.x+c10.y*c10.y;
	Flt rdiff, rsum, root, dinv, alpha;
	if(dsq<=SMALL*SMALL) return 0;	/* common origin */
	rdiff=r1sq-r0sq;
	rsum=r0sq+r1sq;
	root=2.*rsum*dsq-dsq*dsq-rdiff*rdiff;
	if(root<-SMALL) return 0;	/* circles don't touch */
	dinv=.5/dsq;
	alpha=.5-rdiff*dinv;
	p=dlerp(c0, c10, alpha);
	if(root<SMALL){			/* circles just touch */
		i[0]=p;
		return 1;
	}
	root=dinv*sqrt(root);
	d.x=-c10.y*root;
	d.y=c10.x*root;
	i[0]=dadd(p, d);
	i[1]=dsub(p, d);
	return 2;
}
/*
 * Compute intersections of a segment (p0, p1) and circle (cen, r).
 * Return number of intersections, store values through i[01]
 */
int segintercircle(Dpoint p0, Dpoint p1, Dpoint cen, Flt r, Dpoint *i){
	Dpoint d0, pc;
	Flt a, b, det, num;
	int ninter;
	d0=dsub(p1, p0);		/* p=p0 + d0*alpha */
	pc=dsub(p0, cen);
	/*
	 * a*alpha*alpha + 2*b*alpha + c == 0, where
	 * a=dot(d0, d0)
	 * b=dot(d0, pc)
	 * c=dot(pc, pc) - r*r
	 */
	a=d0.x*d0.x+d0.y*d0.y;		/* cannot be negative */
	if(a<SMALL) return 0;		/* degenerate segment: shouldn't happen */
	b=d0.x*pc.x+d0.y*pc.y;
	det=b*b-a*(pc.x*pc.x+pc.y*pc.y-r*r);
	if(det<0) return 0;		/* miss circle? */
	det=sqrt(det);
	num=-b-det;
	ninter=0;
	if(0<=num && num<=a){
		*i++=dlerp(p0, d0, num/a);
		ninter++;
	}
	num=-b+det;
	if(0<=num && num<=a){
		*i=dlerp(p0, d0, num/a);
		ninter++;
	}
	return ninter;
}
/*
 * Store intersection of segments (p0, p1), (q0, q1) in *i.
 * Return number of intersections (0 or 1).
 */
int seginterseg(Dpoint p0, Dpoint p1, Dpoint q0, Dpoint q1, Dpoint *i){
	Flt den, alpha, beta;
	Dpoint dp, dq, pq;
	dp=dsub(p1, p0);			/* p=p0+dp*alpha/den */
	dq=dsub(q1, q0);			/* p=q0+dq*beta/den */
	den=dq.x*dp.y-dp.x*dq.y;
	if(den==0) return 0;			/* parallel */
	pq=dsub(q0, p0);
	alpha=pq.y*dq.x-pq.x*dq.y;
	beta=pq.y*dp.x-pq.x*dp.y;
	if(den<0){
		den=-den;
		alpha=-alpha;
		beta=-beta;
	}
	if(alpha<0 || den<alpha			/* off the end of i0, or */
	|| beta<0 || den<beta) return 0;	/* off the end of i1 */
	*i=dlerp(p0, dp, alpha/den);
	return 1;
}
Flt dist(Dpoint p, Dpoint q){
	p.x-=q.x;
	p.y-=q.y;
	return sqrt(p.x*p.x+p.y*p.y);
}
/*
 * Compute intersections of a segment (p0, p1) and arc (a0, a1, a2).
 * Return number of intersections, store values through i[01]
 */
int seginterarc(Dpoint p0, Dpoint p1, Dpoint a0, Dpoint a1, Dpoint a2, Dpoint *i){
	Dpoint cen, ia[2];
	Flt r, area;
	int ninter=0, n, j;
	if(pldist(a0, a1, a2)<CLOSE) return seginterseg(p0, p1, a0, a2, i);
	cen=circumcenter(a0, a1, a2);
	r=dist(cen, a0);
	n=segintercircle(p0, p1, cen, r, ia);
	if(n==0) return 0;
	area=triarea(a0, a1, a2);
	for(j=0;j!=n;j++)
		if(area*triarea(a0, ia[j], a2)>=0.){
			*i++=ia[j];
			ninter++;
		}
	return ninter;
}
int circinterarc(Dpoint cen, Flt r, Dpoint a0, Dpoint a1, Dpoint a2, Dpoint *i){
	Dpoint acen, ia[2];
	Flt ar, area;
	int ninter=0, n, j;
	if(pldist(a0, a1, a2)<CLOSE) return segintercircle(a0, a2, cen, r, i);
	acen=circumcenter(a0, a1, a2);
	ar=dist(acen, a0);
	n=circintercirc(acen, ar, cen, r, ia);
	if(n==0) return 0;
	area=triarea(a0, a1, a2);
	for(j=0;j!=n;j++)
		if(area*triarea(a0, ia[j], a2)>=0.){
			*i++=ia[j];
			ninter++;
		}
	return ninter;
}
int arcinterarc(Dpoint a0, Dpoint a1, Dpoint a2, Dpoint b0, Dpoint b1, Dpoint b2, Dpoint *i){
	Dpoint acen, ia[2];
	Flt ar, area;
	int ninter=0, n, j;
	if(pldist(a0, a1, a2)<CLOSE) return seginterarc(a0, a2, b0, b1, b2, i);
	acen=circumcenter(a0, a1, a2);
	ar=dist(acen, a0);
	n=circinterarc(acen, ar, b0, b1, b2, ia);
	if(n==0) return 0;
	area=triarea(a0, a1, a2);
	for(j=0;j!=n;j++)
		if(area*triarea(a0, ia[j], a2)>=0.){
			*i++=ia[j];
			ninter++;
		}
	return ninter;
}	
int dptinrect(Dpoint p, Drectangle r){
	return r.min.x<=p.x && p.x<=r.max.x && r.min.y<=p.y && p.y<=r.max.y;
}
int drectxrect(Drectangle r1, Drectangle r2){
	return r1.min.x<=r2.max.x && r2.min.x<=r1.max.x
	    && r1.min.y<=r2.max.y && r2.min.y<=r1.max.y;
}
Drectangle drcanon(Drectangle r){
	Flt t;
	if(r.min.x>r.max.x){ t=r.min.x; r.min.x=r.max.x; r.max.x=t; }
	if(r.min.y>r.max.y){ t=r.min.y; r.min.y=r.max.y; r.max.y=t; }
	return r;
}
/*
 * distance from point p to line [p0,p1]
 */
Flt pldist(Dpoint p, Dpoint p0, Dpoint p1){
	Dpoint d, e;
	Flt dd, de, dsq;
	d=dsub(p1, p0);
	e=dsub(p, p0);
	dd=d.x*d.x+d.y*d.y;
	de=d.x*e.x+d.y*e.y;
	if(dd<SMALL*SMALL) return sqrt(e.x*e.x+e.y*e.y);
	dsq=e.x*e.x+e.y*e.y-de*de/dd;
	if(dsq<SMALL*SMALL) return 0;
	return sqrt(dsq);
}
Drectangle dunion(Drectangle r, Drectangle s){
	if(s.min.x<r.min.x) r.min.x=s.min.x;
	if(s.min.y<r.min.y) r.min.y=s.min.y;
	if(s.max.x>r.max.x) r.max.x=s.max.x;
	if(s.max.y>r.max.y) r.max.y=s.max.y;
	return r;
}
Drectangle draddp(Drectangle r, Dpoint p){
	return Drpt(dadd(r.min, p), dadd(r.max, p));
}

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.