xref: /plan9-contrib/sys/src/cmd/plot/libplot/fill.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier /*
2*3e12c5d1SDavid du Colombier  * fill -- polygon tiler
3*3e12c5d1SDavid du Colombier  * Updating the edgelist from scanline to scanline could be quicker if no
4*3e12c5d1SDavid du Colombier  * edges cross:  we can just merge the incoming edges.  If the scan-line
5*3e12c5d1SDavid du Colombier  * filling routine were a parameter, we could do textured
6*3e12c5d1SDavid du Colombier  * polygons, polyblt, and other such stuff.
7*3e12c5d1SDavid du Colombier  */
8*3e12c5d1SDavid du Colombier #include "mplot.h"
9*3e12c5d1SDavid du Colombier typedef enum{
10*3e12c5d1SDavid du Colombier 	Odd=1,
11*3e12c5d1SDavid du Colombier 	Nonzero=~0
12*3e12c5d1SDavid du Colombier }Windrule;
13*3e12c5d1SDavid du Colombier typedef struct edge Edge;
14*3e12c5d1SDavid du Colombier struct edge{
15*3e12c5d1SDavid du Colombier 	Point p;	/* point of crossing current scan-line */
16*3e12c5d1SDavid du Colombier 	int maxy;	/* scan line at which to discard edge */
17*3e12c5d1SDavid du Colombier 	int dx;		/* x increment if x fraction<1 */
18*3e12c5d1SDavid du Colombier 	int dx1;	/* x increment if x fraction>=1 */
19*3e12c5d1SDavid du Colombier 	int x;		/* x fraction, scaled by den */
20*3e12c5d1SDavid du Colombier 	int num;	/* x fraction increment for unit y change, scaled by den */
21*3e12c5d1SDavid du Colombier 	int den;	/* x fraction increment for unit x change, scaled by num */
22*3e12c5d1SDavid du Colombier 	int dwind;	/* increment of winding number on passing this edge */
23*3e12c5d1SDavid du Colombier 	Edge *next;	/* next edge on current scanline */
24*3e12c5d1SDavid du Colombier 	Edge *prev;	/* previous edge on current scanline */
25*3e12c5d1SDavid du Colombier };
26*3e12c5d1SDavid du Colombier static void insert(Edge *ep, Edge **yp){
27*3e12c5d1SDavid du Colombier 	while(*yp && (*yp)->p.x<ep->p.x) yp=&(*yp)->next;
28*3e12c5d1SDavid du Colombier 	ep->next=*yp;
29*3e12c5d1SDavid du Colombier 	*yp=ep;
30*3e12c5d1SDavid du Colombier 	if(ep->next){
31*3e12c5d1SDavid du Colombier 		ep->prev=ep->next->prev;
32*3e12c5d1SDavid du Colombier 		ep->next->prev=ep;
33*3e12c5d1SDavid du Colombier 		if(ep->prev)
34*3e12c5d1SDavid du Colombier 			ep->prev->next=ep;
35*3e12c5d1SDavid du Colombier 	}
36*3e12c5d1SDavid du Colombier 	else
37*3e12c5d1SDavid du Colombier 		ep->prev=0;
38*3e12c5d1SDavid du Colombier }
39*3e12c5d1SDavid du Colombier static void polygon(int cnt[], double *pts[], Windrule w, int v, Fcode f){
40*3e12c5d1SDavid du Colombier 	Edge *edges, *ep, *nextep, **ylist, **eylist, **yp;
41*3e12c5d1SDavid du Colombier 	Point p, q, p0, p1, p10;
42*3e12c5d1SDavid du Colombier 	int i, dy, nbig, y, left, right, wind, nwind, nvert;
43*3e12c5d1SDavid du Colombier 	int *cntp;
44*3e12c5d1SDavid du Colombier 	double **ptsp, *xp;
45*3e12c5d1SDavid du Colombier 	nvert=0;
46*3e12c5d1SDavid du Colombier 	for(cntp=cnt;*cntp;cntp++) nvert+=*cntp;
47*3e12c5d1SDavid du Colombier 	edges=(Edge *)malloc(nvert*sizeof(Edge));
48*3e12c5d1SDavid du Colombier 	if(edges==0){
49*3e12c5d1SDavid du Colombier 	NoSpace:
50*3e12c5d1SDavid du Colombier 		fprintf(stderr, "polygon: no space\n");
51*3e12c5d1SDavid du Colombier 		exits("malloc failed");
52*3e12c5d1SDavid du Colombier 	}
53*3e12c5d1SDavid du Colombier 	ylist=(Edge **)malloc((screen.r.max.y-screen.r.min.y)*sizeof(Edge *));
54*3e12c5d1SDavid du Colombier 	if(ylist==0) goto NoSpace;
55*3e12c5d1SDavid du Colombier 	eylist=ylist+(screen.r.max.y-screen.r.min.y);
56*3e12c5d1SDavid du Colombier 	for(yp=ylist;yp!=eylist;yp++) *yp=0;
57*3e12c5d1SDavid du Colombier 	ep=edges;
58*3e12c5d1SDavid du Colombier 	for(cntp=cnt,ptsp=pts;*cntp;cntp++,ptsp++){
59*3e12c5d1SDavid du Colombier 		p.x=SCX((*ptsp)[*cntp*2-2]);
60*3e12c5d1SDavid du Colombier 		p.y=SCY((*ptsp)[*cntp*2-1]);
61*3e12c5d1SDavid du Colombier 		nvert=*cntp;
62*3e12c5d1SDavid du Colombier 		for(xp=*ptsp,i=0;i!=nvert;xp+=2,i++){
63*3e12c5d1SDavid du Colombier 			q=p;
64*3e12c5d1SDavid du Colombier 			p.x=SCX(xp[0]);
65*3e12c5d1SDavid du Colombier 			p.y=SCY(xp[1]);
66*3e12c5d1SDavid du Colombier 			if(p.y==q.y) continue;
67*3e12c5d1SDavid du Colombier 			if(p.y<q.y){
68*3e12c5d1SDavid du Colombier 				p0=p;
69*3e12c5d1SDavid du Colombier 				p1=q;
70*3e12c5d1SDavid du Colombier 				ep->dwind=1;
71*3e12c5d1SDavid du Colombier 			}
72*3e12c5d1SDavid du Colombier 			else{
73*3e12c5d1SDavid du Colombier 				p0=q;
74*3e12c5d1SDavid du Colombier 				p1=p;
75*3e12c5d1SDavid du Colombier 				ep->dwind=-1;
76*3e12c5d1SDavid du Colombier 			}
77*3e12c5d1SDavid du Colombier 			if(p1.y<=screen.r.min.y) continue;
78*3e12c5d1SDavid du Colombier 			if(p0.y>=screen.r.max.y) continue;
79*3e12c5d1SDavid du Colombier 			ep->p=p0;
80*3e12c5d1SDavid du Colombier 			if(p1.y>screen.r.max.y)
81*3e12c5d1SDavid du Colombier 				ep->maxy=screen.r.max.y;
82*3e12c5d1SDavid du Colombier 			else
83*3e12c5d1SDavid du Colombier 				ep->maxy=p1.y;
84*3e12c5d1SDavid du Colombier 			p10=sub(p1, p0);
85*3e12c5d1SDavid du Colombier 			if(p10.x>=0){
86*3e12c5d1SDavid du Colombier 				ep->dx=p10.x/p10.y;
87*3e12c5d1SDavid du Colombier 				ep->dx1=ep->dx+1;
88*3e12c5d1SDavid du Colombier 			}
89*3e12c5d1SDavid du Colombier 			else{
90*3e12c5d1SDavid du Colombier 				p10.x=-p10.x;
91*3e12c5d1SDavid du Colombier 				ep->dx=-(p10.x/p10.y); /* this nonsense rounds toward zero */
92*3e12c5d1SDavid du Colombier 				ep->dx1=ep->dx-1;
93*3e12c5d1SDavid du Colombier 			}
94*3e12c5d1SDavid du Colombier 			ep->x=0;
95*3e12c5d1SDavid du Colombier 			ep->num=p10.x%p10.y;
96*3e12c5d1SDavid du Colombier 			ep->den=p10.y;
97*3e12c5d1SDavid du Colombier 			if(ep->p.y<screen.r.min.y){
98*3e12c5d1SDavid du Colombier 				dy=screen.r.min.y-ep->p.y;
99*3e12c5d1SDavid du Colombier 				ep->x+=dy*ep->num;
100*3e12c5d1SDavid du Colombier 				nbig=ep->x/ep->den;
101*3e12c5d1SDavid du Colombier 				ep->p.x+=ep->dx1*nbig+ep->dx*(dy-nbig);
102*3e12c5d1SDavid du Colombier 				ep->x%=ep->den;
103*3e12c5d1SDavid du Colombier 				ep->p.y=screen.r.min.y;
104*3e12c5d1SDavid du Colombier 			}
105*3e12c5d1SDavid du Colombier 			insert(ep, ylist+(ep->p.y-screen.r.min.y));
106*3e12c5d1SDavid du Colombier 			ep++;
107*3e12c5d1SDavid du Colombier 		}
108*3e12c5d1SDavid du Colombier 	}
109*3e12c5d1SDavid du Colombier 	left = 0;
110*3e12c5d1SDavid du Colombier 	for(yp=ylist,y=screen.r.min.y;yp!=eylist;yp++,y++){
111*3e12c5d1SDavid du Colombier 		wind=0;
112*3e12c5d1SDavid du Colombier 		for(ep=*yp;ep;ep=nextep){
113*3e12c5d1SDavid du Colombier 			nwind=wind+ep->dwind;
114*3e12c5d1SDavid du Colombier 			if(nwind&w){	/* inside */
115*3e12c5d1SDavid du Colombier 				if(!(wind&w)){
116*3e12c5d1SDavid du Colombier 					left=ep->p.x;
117*3e12c5d1SDavid du Colombier 					if(left<screen.r.min.x) left=screen.r.min.x;
118*3e12c5d1SDavid du Colombier 				}
119*3e12c5d1SDavid du Colombier 			}
120*3e12c5d1SDavid du Colombier 			else if(wind&w){
121*3e12c5d1SDavid du Colombier 				right=ep->p.x;
122*3e12c5d1SDavid du Colombier 				if(right>=screen.r.max.x) right=screen.r.max.x;
123*3e12c5d1SDavid du Colombier #ifdef BART_BUG_FIXED
124*3e12c5d1SDavid du Colombier 				if(right>left)
125*3e12c5d1SDavid du Colombier 					segment(&screen, Pt(left, y), Pt(right, y), v, f);
126*3e12c5d1SDavid du Colombier #else
127*3e12c5d1SDavid du Colombier 				if(right>left){
128*3e12c5d1SDavid du Colombier 					switch(v){
129*3e12c5d1SDavid du Colombier 					default:
130*3e12c5d1SDavid du Colombier 						segment(&screen, Pt(left, y), Pt(right, y),
131*3e12c5d1SDavid du Colombier 							~0, D&~S);
132*3e12c5d1SDavid du Colombier 						segment(&screen, Pt(left, y), Pt(right, y),
133*3e12c5d1SDavid du Colombier 							v, f);
134*3e12c5d1SDavid du Colombier 						break;
135*3e12c5d1SDavid du Colombier 					case 0:
136*3e12c5d1SDavid du Colombier 						segment(&screen, Pt(left, y), Pt(right, y),
137*3e12c5d1SDavid du Colombier 							~0, D&~S);
138*3e12c5d1SDavid du Colombier 						break;
139*3e12c5d1SDavid du Colombier 					case 3:
140*3e12c5d1SDavid du Colombier 						segment(&screen, Pt(left, y), Pt(right, y),
141*3e12c5d1SDavid du Colombier 							v, f);
142*3e12c5d1SDavid du Colombier 						break;
143*3e12c5d1SDavid du Colombier 					}
144*3e12c5d1SDavid du Colombier 				}
145*3e12c5d1SDavid du Colombier #endif
146*3e12c5d1SDavid du Colombier 			}
147*3e12c5d1SDavid du Colombier 			wind=nwind;
148*3e12c5d1SDavid du Colombier 			nextep=ep->next;
149*3e12c5d1SDavid du Colombier 			if(++ep->p.y!=ep->maxy){
150*3e12c5d1SDavid du Colombier 				ep->x+=ep->num;
151*3e12c5d1SDavid du Colombier 				if(ep->x>=ep->den){
152*3e12c5d1SDavid du Colombier 					ep->x-=ep->den;
153*3e12c5d1SDavid du Colombier 					ep->p.x+=ep->dx1;
154*3e12c5d1SDavid du Colombier 				}
155*3e12c5d1SDavid du Colombier 				else
156*3e12c5d1SDavid du Colombier 					ep->p.x+=ep->dx;
157*3e12c5d1SDavid du Colombier 				insert(ep, yp+1);
158*3e12c5d1SDavid du Colombier 			}
159*3e12c5d1SDavid du Colombier 		}
160*3e12c5d1SDavid du Colombier 	}
161*3e12c5d1SDavid du Colombier 	free((char *)edges);
162*3e12c5d1SDavid du Colombier 	free((char *)ylist);
163*3e12c5d1SDavid du Colombier }
164*3e12c5d1SDavid du Colombier void fill(int num[], double *ff[]){
165*3e12c5d1SDavid du Colombier 	polygon(num, ff, Odd, e1->foregr, S);
166*3e12c5d1SDavid du Colombier }
167