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

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


#include "art.h"

Image *blue;

/*
 * code to maintain alignment data structure (global variable active).
 */
void activateprim(Item *ip, Item *op){
	if(op->flags&HOT) (*ip->fn->activate)(ip);
}
void activate(Item *ip){
	walk(ip, scoffs, activateprim);
}
void hotline(Dpoint p, Dpoint q, int ep){
	Dpoint d, r;
	int i;
	Flt ang, l;
	if(ep&L) hotpoint(p);
	if(ep&R) hotpoint(q);
	d=dsub(q, p);
	l=dlen(d);
	if(l<SMALL){ msg("tiny line"); return; }
	ang=datan2(d.y, d.x);
	for(i=0;i!=nalign[ANGLE];i++) if(align[ANGLE][i].active){
		if(ep&L) alline(p, ang+align[ANGLE][i].value);
		if(ep&R) alline(q, ang+align[ANGLE][i].value);
	}
	for(i=0;i!=nalign[PARA];i++) if(align[PARA][i].active){
		r.x=d.y*align[PARA][i].value/l;
		r.y=-d.x*align[PARA][i].value/l;
		alline(dadd(p, r), ang);
		alline(dsub(p, r), ang);
	}
}
void hotarc(Dpoint p, Dpoint q, Dpoint r){
	Dpoint cen, d;
	int i;
	Flt pang, rang;
	if(pldist(p, q, r)<CLOSE){
		hotline(p, r, L|R);
		return;
	}
	hotpoint(p);
	hotpoint(q);
	cen=circumcenter(p, q, r);
	d=dsub(p, cen);
	pang=datan2(d.x, -d.y);
	d=dsub(r, cen);
	rang=datan2(d.x, -d.y);
	for(i=0;i!=nalign[ANGLE];i++) if(align[ANGLE][i].active){
		alline(p, pang+align[ANGLE][i].value);
		alline(r, rang+align[ANGLE][i].value);
	}
}
void hotpoint(Dpoint p){
	int i;
	for(i=0;i!=nalign[SLOPE];i++) if(align[SLOPE][i].active)
		alline(p, align[SLOPE][i].value);
	for(i=0;i!=nalign[CIRC];i++)
		if(align[CIRC][i].active)
			alcirc(p, align[CIRC][i].value);
}
/*
 * add an alignment line through p at angle t
 */
void alline(Dpoint p, Flt t){
	Dpoint p0, p1, d;
	Item *ip;

	d.x=2000.*cos(radians(t));
	d.y=2000.*sin(radians(t));
	p0=dsub(p, d);
	p1=dadd(p, d);
	if(dclipline(dwgdrect, &p0, &p1) && !findline(active, p0, p1)){
		ip=addline(active, p0, p1);
		itemdraw(ip, Dpt(0., 0.), blue);	/*S|D */
	}
}
/*
 * add an alignment circle through p with radius r
 */
void alcirc(Dpoint p, Flt r){
	Item *ip;

	if(!findcircle(active, p, r)){
		ip=addcircle(active, p, r);
		itemdraw(ip, Dpt(0., 0.), blue);	/*S|D */
	}
}
int findline(Item *ip, Dpoint p, Dpoint q){
	Item *cp;
	switch(ip->type){
	default: return 0;
	case LINE:
		return deqpt(ip->p[0], p) && deqpt(ip->p[1], q)
		    || deqpt(ip->p[0], q) && deqpt(ip->p[1], p);
	case HEAD:
		for(cp=ip->next;cp!=ip;cp=cp->next)
			if(findline(cp, p, q)) return 1;
		return 0;
	}
}
int findcircle(Item *ip, Dpoint p, Flt r){
	Item *cp;
	switch(ip->type){
	default:
		return 0;
	case CIRCLE:
		return deqpt(ip->p[0], p) && same(ip->r, r);
	case HEAD:
		for(cp=ip->next;cp!=ip;cp=cp->next)
			if(findcircle(cp, p, r)) return 1;
		return 0;
	}
}
#define	code(p)	((p->x<xl?1:p->x>xr?2:0)|(p->y>yt?4:p->y<yb?8:0))
#define	xl r.min.x
#define	yb r.min.y
#define	xr r.max.x
#define yt r.max.y
#define	x0 p0->x
#define	y0 p0->y
#define	x1 p1->x
#define	y1 p1->y
int dclipline(Drectangle r, Dpoint *p0, Dpoint *p1){
	int c0=code(p0), c1=code(p1), c;
	Dpoint t;
	while(c0|c1){
		if(c0&c1) return 0;
		c=c0?c0:c1;
		if(c&1)     t.y=y0+(y1-y0)*(xl-x0)/(x1-x0), t.x=xl;
		else if(c&2)t.y=y0+(y1-y0)*(xr-x0)/(x1-x0), t.x=xr;
		else if(c&4)t.x=x0+(x1-x0)*(yt-y0)/(y1-y0), t.y=yt;
		else        t.x=x0+(x1-x0)*(yb-y0)/(y1-y0), t.y=yb;
		if(c==c0) *p0=t, c0=code(p0);
		else      *p1=t, c1=code(p1);
	}
	return 1;
}
void Oheat(void){
	if(selection){
		heat(selection);
		activate(selection);
	}
	else msg("heat: nothing selected");
}
/*
 * turn a's HOT flags on
 */
void heat(Item *a){
	Item *ip;
	if(a->type==HEAD)
		for(ip=a->next;ip!=a;ip=ip->next)
			heat(ip);
	else a->flags|=HOT;
}
void Ocoolall(void){
	cool(scene);
	delete(active);
	active=addhead();
	redraw();
	reheat();
}
/*
 * turn a's HOT flags off
 */
void cool(Item *a){
	Item *p;
	a->flags&=~HOT;
	if(a->type==HEAD){
		for(p=a->next;p!=a;p=p->next)
			cool(p);
	}
}
/*
 * get intersections of two objects
 * Missing cases:
 *	spline-circle
 *	spline-arc
 */
int itemxitem(Item *p, Item *q, Dpoint *i){
	Item r, *t;
	int n;
	Dpoint pt[2];
	if(p==q && p->type!=SPLINE) return 0;
	if(q->type==BOX){
		t=p;
		p=q;
		q=t;
	}
	switch(p->type){
	case BOX:
		r.type=LINE;
		r.p=pt;
		r.np=2;
		r.p[0]=p->p[0];
		r.p[1]=Dpt(p->p[0].x, p->p[1].y);
		n=itemxitem(q, &r, i);
		r.p[0]=p->p[1];
		n+=itemxitem(q, &r, i+n);
		r.p[1]=Dpt(p->p[1].x, p->p[0].y);
		n+=itemxitem(q, &r, i+n);
		r.p[0]=p->p[0];
		return n+itemxitem(q, &r, i+n);
	case LINE:
		switch(q->type){
		case LINE:	return seginterseg(p->p[0], p->p[1], q->p[0], q->p[1], i);
		case CIRCLE:	return segintercircle(p->p[0], p->p[1], q->p[0], q->r, i);
		case ARC:	return seginterarc(p->p[0], p->p[1], q->p[0], q->p[1], q->p[2], i);
		case SPLINE:	return seginterspline(p->p[0], p->p[1], q, i);
		}
		break;
	case CIRCLE:
		switch(q->type){
		case LINE:	return segintercircle(q->p[0], q->p[1], p->p[0], p->r, i);
		case CIRCLE:	return circintercirc(p->p[0], p->r, q->p[0], q->r, i);
		case ARC:	return circinterarc(p->p[0], p->r, q->p[0], q->p[1], q->p[2], i);
		}
		break;
	case ARC:
		switch(q->type){
		case LINE:	return seginterarc(q->p[0], q->p[1], p->p[0], p->p[1], p->p[2], i);
		case CIRCLE:	return circinterarc(q->p[0], q->r, p->p[0], p->p[1], p->p[2], i);
		case ARC:	return arcinterarc(p->p[0],p->p[1],p->p[2], q->p[0],q->p[1],q->p[2], i);
		}
	case SPLINE:
		switch(q->type){
		case LINE:	return seginterspline(q->p[0], q->p[1], p, i);
		case SPLINE:	return splineinterspline(p, q, i);
		}
	}
	return 0;	/* missing cases behave as if no intersection */
}
void reheat(void){
	delete(active);
	active=addhead();
	redraw();
	activate(scene);
}
void flatten(Item *ip, Item *op){
	ip=additemv(active, ip->type, ip->r, ip->face, ip->text, ip->group, ip->fn,
		ip->np, ip->p, Dpt(0., 0.));
	ip->flags|=FLAT|INVIS;	/* INVIS because the originals are already visible */
	ip->orig=op;
}
void realign(void){
	Item *ip, *next;
	for(ip=active->next;ip!=active;ip=next){
		next=ip->next;
		if(ip->flags&FLAT) delete(ip);
	}
	mwalk(scene, scoffs, flatten);
}

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.