xref: /plan9/sys/src/cmd/plot/libplot/fill.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier  * fill -- polygon tiler
33e12c5d1SDavid du Colombier  * Updating the edgelist from scanline to scanline could be quicker if no
43e12c5d1SDavid du Colombier  * edges cross:  we can just merge the incoming edges.  If the scan-line
53e12c5d1SDavid du Colombier  * filling routine were a parameter, we could do textured
63e12c5d1SDavid du Colombier  * polygons, polyblt, and other such stuff.
73e12c5d1SDavid du Colombier  */
83e12c5d1SDavid du Colombier #include "mplot.h"
93e12c5d1SDavid du Colombier typedef enum{
103e12c5d1SDavid du Colombier 	Odd=1,
113e12c5d1SDavid du Colombier 	Nonzero=~0
123e12c5d1SDavid du Colombier }Windrule;
133e12c5d1SDavid du Colombier typedef struct edge Edge;
143e12c5d1SDavid du Colombier struct edge{
153e12c5d1SDavid du Colombier 	Point p;	/* point of crossing current scan-line */
163e12c5d1SDavid du Colombier 	int maxy;	/* scan line at which to discard edge */
173e12c5d1SDavid du Colombier 	int dx;		/* x increment if x fraction<1 */
183e12c5d1SDavid du Colombier 	int dx1;	/* x increment if x fraction>=1 */
193e12c5d1SDavid du Colombier 	int x;		/* x fraction, scaled by den */
203e12c5d1SDavid du Colombier 	int num;	/* x fraction increment for unit y change, scaled by den */
213e12c5d1SDavid du Colombier 	int den;	/* x fraction increment for unit x change, scaled by num */
223e12c5d1SDavid du Colombier 	int dwind;	/* increment of winding number on passing this edge */
233e12c5d1SDavid du Colombier 	Edge *next;	/* next edge on current scanline */
243e12c5d1SDavid du Colombier 	Edge *prev;	/* previous edge on current scanline */
253e12c5d1SDavid du Colombier };
insert(Edge * ep,Edge ** yp)263e12c5d1SDavid du Colombier static void insert(Edge *ep, Edge **yp){
273e12c5d1SDavid du Colombier 	while(*yp && (*yp)->p.x<ep->p.x) yp=&(*yp)->next;
283e12c5d1SDavid du Colombier 	ep->next=*yp;
293e12c5d1SDavid du Colombier 	*yp=ep;
303e12c5d1SDavid du Colombier 	if(ep->next){
313e12c5d1SDavid du Colombier 		ep->prev=ep->next->prev;
323e12c5d1SDavid du Colombier 		ep->next->prev=ep;
333e12c5d1SDavid du Colombier 		if(ep->prev)
343e12c5d1SDavid du Colombier 			ep->prev->next=ep;
353e12c5d1SDavid du Colombier 	}
363e12c5d1SDavid du Colombier 	else
373e12c5d1SDavid du Colombier 		ep->prev=0;
383e12c5d1SDavid du Colombier }
polygon(int cnt[],double * pts[],Windrule w,int v)39*7dd7cddfSDavid du Colombier static void polygon(int cnt[], double *pts[], Windrule w, int v){
403e12c5d1SDavid du Colombier 	Edge *edges, *ep, *nextep, **ylist, **eylist, **yp;
413e12c5d1SDavid du Colombier 	Point p, q, p0, p1, p10;
423e12c5d1SDavid du Colombier 	int i, dy, nbig, y, left, right, wind, nwind, nvert;
433e12c5d1SDavid du Colombier 	int *cntp;
443e12c5d1SDavid du Colombier 	double **ptsp, *xp;
453e12c5d1SDavid du Colombier 	nvert=0;
463e12c5d1SDavid du Colombier 	for(cntp=cnt;*cntp;cntp++) nvert+=*cntp;
473e12c5d1SDavid du Colombier 	edges=(Edge *)malloc(nvert*sizeof(Edge));
483e12c5d1SDavid du Colombier 	if(edges==0){
493e12c5d1SDavid du Colombier 	NoSpace:
503e12c5d1SDavid du Colombier 		fprintf(stderr, "polygon: no space\n");
513e12c5d1SDavid du Colombier 		exits("malloc failed");
523e12c5d1SDavid du Colombier 	}
53*7dd7cddfSDavid du Colombier 	ylist=(Edge **)malloc(Dy(screen->r)*sizeof(Edge *));
543e12c5d1SDavid du Colombier 	if(ylist==0) goto NoSpace;
55*7dd7cddfSDavid du Colombier 	eylist=ylist+Dy(screen->r);
563e12c5d1SDavid du Colombier 	for(yp=ylist;yp!=eylist;yp++) *yp=0;
573e12c5d1SDavid du Colombier 	ep=edges;
583e12c5d1SDavid du Colombier 	for(cntp=cnt,ptsp=pts;*cntp;cntp++,ptsp++){
593e12c5d1SDavid du Colombier 		p.x=SCX((*ptsp)[*cntp*2-2]);
603e12c5d1SDavid du Colombier 		p.y=SCY((*ptsp)[*cntp*2-1]);
613e12c5d1SDavid du Colombier 		nvert=*cntp;
623e12c5d1SDavid du Colombier 		for(xp=*ptsp,i=0;i!=nvert;xp+=2,i++){
633e12c5d1SDavid du Colombier 			q=p;
643e12c5d1SDavid du Colombier 			p.x=SCX(xp[0]);
653e12c5d1SDavid du Colombier 			p.y=SCY(xp[1]);
663e12c5d1SDavid du Colombier 			if(p.y==q.y) continue;
673e12c5d1SDavid du Colombier 			if(p.y<q.y){
683e12c5d1SDavid du Colombier 				p0=p;
693e12c5d1SDavid du Colombier 				p1=q;
703e12c5d1SDavid du Colombier 				ep->dwind=1;
713e12c5d1SDavid du Colombier 			}
723e12c5d1SDavid du Colombier 			else{
733e12c5d1SDavid du Colombier 				p0=q;
743e12c5d1SDavid du Colombier 				p1=p;
753e12c5d1SDavid du Colombier 				ep->dwind=-1;
763e12c5d1SDavid du Colombier 			}
77*7dd7cddfSDavid du Colombier 			if(p1.y<=screen->r.min.y) continue;
78*7dd7cddfSDavid du Colombier 			if(p0.y>=screen->r.max.y) continue;
793e12c5d1SDavid du Colombier 			ep->p=p0;
80*7dd7cddfSDavid du Colombier 			if(p1.y>screen->r.max.y)
81*7dd7cddfSDavid du Colombier 				ep->maxy=screen->r.max.y;
823e12c5d1SDavid du Colombier 			else
833e12c5d1SDavid du Colombier 				ep->maxy=p1.y;
84*7dd7cddfSDavid du Colombier 			p10=subpt(p1, p0);
853e12c5d1SDavid du Colombier 			if(p10.x>=0){
863e12c5d1SDavid du Colombier 				ep->dx=p10.x/p10.y;
873e12c5d1SDavid du Colombier 				ep->dx1=ep->dx+1;
883e12c5d1SDavid du Colombier 			}
893e12c5d1SDavid du Colombier 			else{
903e12c5d1SDavid du Colombier 				p10.x=-p10.x;
913e12c5d1SDavid du Colombier 				ep->dx=-(p10.x/p10.y); /* this nonsense rounds toward zero */
923e12c5d1SDavid du Colombier 				ep->dx1=ep->dx-1;
933e12c5d1SDavid du Colombier 			}
943e12c5d1SDavid du Colombier 			ep->x=0;
953e12c5d1SDavid du Colombier 			ep->num=p10.x%p10.y;
963e12c5d1SDavid du Colombier 			ep->den=p10.y;
97*7dd7cddfSDavid du Colombier 			if(ep->p.y<screen->r.min.y){
98*7dd7cddfSDavid du Colombier 				dy=screen->r.min.y-ep->p.y;
993e12c5d1SDavid du Colombier 				ep->x+=dy*ep->num;
1003e12c5d1SDavid du Colombier 				nbig=ep->x/ep->den;
1013e12c5d1SDavid du Colombier 				ep->p.x+=ep->dx1*nbig+ep->dx*(dy-nbig);
1023e12c5d1SDavid du Colombier 				ep->x%=ep->den;
103*7dd7cddfSDavid du Colombier 				ep->p.y=screen->r.min.y;
1043e12c5d1SDavid du Colombier 			}
105*7dd7cddfSDavid du Colombier 			insert(ep, ylist+(ep->p.y-screen->r.min.y));
1063e12c5d1SDavid du Colombier 			ep++;
1073e12c5d1SDavid du Colombier 		}
1083e12c5d1SDavid du Colombier 	}
1093e12c5d1SDavid du Colombier 	left = 0;
110*7dd7cddfSDavid du Colombier 	for(yp=ylist,y=screen->r.min.y;yp!=eylist;yp++,y++){
1113e12c5d1SDavid du Colombier 		wind=0;
1123e12c5d1SDavid du Colombier 		for(ep=*yp;ep;ep=nextep){
1133e12c5d1SDavid du Colombier 			nwind=wind+ep->dwind;
1143e12c5d1SDavid du Colombier 			if(nwind&w){	/* inside */
1153e12c5d1SDavid du Colombier 				if(!(wind&w)){
1163e12c5d1SDavid du Colombier 					left=ep->p.x;
117*7dd7cddfSDavid du Colombier 					if(left<screen->r.min.x) left=screen->r.min.x;
1183e12c5d1SDavid du Colombier 				}
1193e12c5d1SDavid du Colombier 			}
1203e12c5d1SDavid du Colombier 			else if(wind&w){
1213e12c5d1SDavid du Colombier 				right=ep->p.x;
122*7dd7cddfSDavid du Colombier 				if(right>=screen->r.max.x) right=screen->r.max.x;
123*7dd7cddfSDavid du Colombier #define BART_BUG_FIXED	/* what goes on here?? -rob */
1243e12c5d1SDavid du Colombier #ifdef BART_BUG_FIXED
1253e12c5d1SDavid du Colombier 				if(right>left)
126*7dd7cddfSDavid du Colombier 					line(screen, Pt(left, y), Pt(right, y), Endsquare, Endsquare, 0, getcolor(v), ZP);
1273e12c5d1SDavid du Colombier #else
1283e12c5d1SDavid du Colombier 				if(right>left){
1293e12c5d1SDavid du Colombier 					switch(v){
1303e12c5d1SDavid du Colombier 					default:
1313e12c5d1SDavid du Colombier 						segment(&screen, Pt(left, y), Pt(right, y),
1323e12c5d1SDavid du Colombier 							~0, D&~S);
1333e12c5d1SDavid du Colombier 						segment(&screen, Pt(left, y), Pt(right, y),
1343e12c5d1SDavid du Colombier 							v, f);
1353e12c5d1SDavid du Colombier 						break;
1363e12c5d1SDavid du Colombier 					case 0:
1373e12c5d1SDavid du Colombier 						segment(&screen, Pt(left, y), Pt(right, y),
1383e12c5d1SDavid du Colombier 							~0, D&~S);
1393e12c5d1SDavid du Colombier 						break;
1403e12c5d1SDavid du Colombier 					case 3:
1413e12c5d1SDavid du Colombier 						segment(&screen, Pt(left, y), Pt(right, y),
1423e12c5d1SDavid du Colombier 							v, f);
1433e12c5d1SDavid du Colombier 						break;
1443e12c5d1SDavid du Colombier 					}
1453e12c5d1SDavid du Colombier 				}
1463e12c5d1SDavid du Colombier #endif
1473e12c5d1SDavid du Colombier 			}
1483e12c5d1SDavid du Colombier 			wind=nwind;
1493e12c5d1SDavid du Colombier 			nextep=ep->next;
1503e12c5d1SDavid du Colombier 			if(++ep->p.y!=ep->maxy){
1513e12c5d1SDavid du Colombier 				ep->x+=ep->num;
1523e12c5d1SDavid du Colombier 				if(ep->x>=ep->den){
1533e12c5d1SDavid du Colombier 					ep->x-=ep->den;
1543e12c5d1SDavid du Colombier 					ep->p.x+=ep->dx1;
1553e12c5d1SDavid du Colombier 				}
1563e12c5d1SDavid du Colombier 				else
1573e12c5d1SDavid du Colombier 					ep->p.x+=ep->dx;
1583e12c5d1SDavid du Colombier 				insert(ep, yp+1);
1593e12c5d1SDavid du Colombier 			}
1603e12c5d1SDavid du Colombier 		}
1613e12c5d1SDavid du Colombier 	}
1623e12c5d1SDavid du Colombier 	free((char *)edges);
1633e12c5d1SDavid du Colombier 	free((char *)ylist);
1643e12c5d1SDavid du Colombier }
fill(int num[],double * ff[])1653e12c5d1SDavid du Colombier void fill(int num[], double *ff[]){
166*7dd7cddfSDavid du Colombier 	polygon(num, ff, Odd, e1->foregr);
1673e12c5d1SDavid du Colombier }
168