diff --git a/src/modules/Image/polyfill.c b/src/modules/Image/polyfill.c index eca89537462d9a4b8a82c44999115eb202d6e72d..641af39306368f69be602b00558c8009f175bab8 100644 --- a/src/modules/Image/polyfill.c +++ b/src/modules/Image/polyfill.c @@ -1,5 +1,5 @@ #include "global.h" -RCSID("$Id: polyfill.c,v 1.11 1997/11/05 03:29:17 mirar Exp $"); +RCSID("$Id: polyfill.c,v 1.12 1997/11/05 03:30:02 mirar Exp $"); /* Prototypes are needed for these */ extern double floor(double); @@ -29,7 +29,7 @@ extern double floor(double); /* **! module Image **! note -**! $Id: polyfill.c,v 1.11 1997/11/05 03:29:17 mirar Exp $ +**! $Id: polyfill.c,v 1.12 1997/11/05 03:30:02 mirar Exp $ **! class image */ @@ -121,16 +121,16 @@ static void vertex_connect(struct vertex *above, static INLINE float vertex_xmax(struct vertex_list *v,float yp,float *ydest) { if (v->dx>0.0) - if (v->below->y>yp+1.0) + if (v->below->y>yp+1.0+1e-10) return v->above->x+v->dx*((*ydest=(yp+1.0))-v->above->y); else return (*ydest=v->below->y),v->below->x; else if (v->dx<0.0) - if (v->above->y<yp) + if (v->above->y<yp-1e-10) return v->above->x+v->dx*((*ydest=yp)-v->above->y); else return (*ydest=v->above->y),v->above->x; - else if (v->below->y>yp+1.0) + else if (v->below->y>yp+1.0+1e-10) return (*ydest=yp+1.0),v->above->x; else return (*ydest=v->below->y),v->below->x; @@ -139,16 +139,16 @@ static INLINE float vertex_xmax(struct vertex_list *v,float yp,float *ydest) static INLINE float vertex_xmin(struct vertex_list *v,float yp,float *ydest) { if (v->dx<0.0) - if (v->below->y>yp+1.0) + if (v->below->y>yp+1.0+1e-10) return v->above->x+v->dx*((*ydest=(yp+1.0))-v->above->y); else return (*ydest=v->below->y),v->below->x; else if (v->dx>0.0) - if (v->above->y<yp) + if (v->above->y<yp-1e-10) return v->above->x+v->dx*((*ydest=yp)-v->above->y); else return (*ydest=v->above->y),v->above->x; - else if (v->above->y<yp) + else if (v->above->y<yp-1e-10) return (*ydest=yp),v->above->x; else return (*ydest=v->above->y),v->above->x; @@ -160,51 +160,72 @@ static void add_vertices(struct vertex_list **first, { struct vertex_list **ins,*c; + c=*first; + while (c) + { + c->xmin=vertex_xmin(c,yp,&c->yxmin); + c->xmax=vertex_xmax(c,yp,&c->yxmax); + c=c->next; + } + while (what) { - float xi,yi; - float xw = what->above->x; - float yw = what->above->y; + what->xmin=vertex_xmin(what,yp,&what->yxmin); + what->xmax=vertex_xmax(what,yp,&what->yxmax); ins=first; #ifdef POLYDEBUG - fprintf(stderr,"insert %g,%g - %g,%g %g xw==%g\n", + fprintf(stderr,"insert %g,%g - %g,%g %g,%g - %g,%g\n", what->above->x,what->above->y, - what->below->x,what->below->y,what->dx,xw); + what->below->x,what->below->y, + what->xmin,what->yxmin, + what->xmax,what->yxmax); #endif - + /* fast jump vectorgroups on the left */ while (*ins) { - if (fabs((*ins)->dy)<1e-10 || fabs(what->dy)<1e-10) xi=xw; - else xi = (*ins)->above->x + (*ins)->dx*(yw-(*ins)->above->y); - yi=yw; - - if (xw<xi && what->dx<0.0) break; - if (xw>xi && what->dx>0.0) break; - - if (xw==xi && -/* ((*ins)->below->x>xw || (*ins)->above->x>xw) &&*/ - (*ins)->dx>what->dx) break; + if ((*ins)->xmax>what->xmin) break; + ins=&((*ins)->next); + } -#ifdef POLYDEBUG - fprintf(stderr," after %g,%g - %g,%g %g i=%g,%g w=%g,%g\n", - (*ins)->above->x,(*ins)->above->y, - (*ins)->below->x,(*ins)->below->y,(*ins)->dx, - xi,yi,xw,yw); + /* ok, place in correct y for x=what->xmin or x=(*ins)->xmin */ -#endif + while (*ins) + { + /* case: -what-> <-ins- */ + if ((*ins)->xmin>=what->xmax) break; /* place left of */ + + /* case: -what- */ + /* <-ins- */ + if ((*ins)->xmin>what->xmin) + { if ((*ins)->yxmin>VY(what,(*ins)->xmin)) break; } + /* case: <-what- */ + /* -ins- */ + else + { if (VY((*ins),what->xmin)>what->yxmin) break; } + + /* case: -what-> */ + /* -ins- */ + if ((*ins)->xmax>what->xmax) + { if (VY((*ins),what->xmax)>what->yxmax) break; } + /* case: -what- */ + /* -ins-> */ + else + { if ((*ins)->yxmax>VY(what,(*ins)->xmax)) break; } ins=&((*ins)->next); } + #ifdef POLYDEBUG if (*ins) - fprintf(stderr," before %g,%g - %g,%g %g i=%g,%g w=%g,%g\n", - (*ins)->above->x,(*ins)->above->y, - (*ins)->below->x,(*ins)->below->y,(*ins)->dy, - xi,yi,xw,yw); + fprintf(stderr," before %g,%g - %g,%g %g,%g - %g,%g\n", + (*ins)->above->x,(*ins)->above->y, + (*ins)->below->x,(*ins)->below->y, + (*ins)->xmin,(*ins)->yxmin, + (*ins)->xmax,(*ins)->yxmax); #endif @@ -225,14 +246,29 @@ static void sub_vertices(struct vertex_list **first, ins=first; +#ifdef POLYDEBUG + fprintf(stderr,"remove %lx %g,%g\n",below,below->x,below->y); +#endif + while (*ins) + { if ((*ins)->below==below) { c=*ins; *ins=(*ins)->next; free(c); } - else ins=&((*ins)->next); + else + { +#ifdef POLYDEBUG + fprintf(stderr,"%g,%g-%g,%g %lx,%lx\n", + (*ins)->above->x,(*ins)->above->y, + (*ins)->below->x,(*ins)->below->y, + (*ins)->above,(*ins)->below); +#endif + ins=&((*ins)->next); + } + } } static void polygone_row_fill(float *buf, @@ -273,18 +309,22 @@ static int polygone_row_vertices(float *buf, fill=fill?-1:1; +#if 1 v=v1; while (v) { - if (v->xmin==xmin && v->yxmin==yp) + if (v->xmin==xmin && v->yxmin==yp && v->above->y<yp + && v->xmin<xmax && v->xmax>xmin) { fill=-fill; #ifdef POLYDEBUG - fprintf(stderr,"aa toggle fill: %d\n",fill); + fprintf(stderr,"aa toggle fill: %d->%d on %g,%g-%g,%g\n", + -fill,fill,v->xmin,v->yxmin,v->xmax,v->yxmax); #endif } v=v->next; } +#endif if (fill<0) polygone_row_fill(buf,xmin,xmax); @@ -292,12 +332,13 @@ static int polygone_row_vertices(float *buf, while (v!=v2) { #ifdef POLYDEBUG - fprintf(stderr,"aa << %g,%g-%g,%g %g,%g-%g,%g fill=%d xofill=%d\n", - v->above->x,v->above->y, - v->below->x,v->below->y, - v->xmin,v->yxmin, - v->xmax,v->yxmax, - fill,xofill); + fprintf(stderr,"aa << %g,%g-%g,%g %g,%g-%g,%g fill=%d xofill=%d xmin=%g xmax=%g xmin_i=%d xmax_i=%d\n", + v->above->x,v->above->y, + v->below->x,v->below->y, + v->xmin,v->yxmin, + v->xmax,v->yxmax, + fill,xofill, + xmin,xmax,xmin_i,xmax_i); #endif if (xmin!=xmax && v->xmin<xmax && v->xmax>xmin) @@ -393,19 +434,20 @@ static int toggle_fill(struct vertex_list *v1, static void polygone_row(struct image *img, float *buf, - struct vertex_list *vertices, + struct vertex_list **vertices, float yp, int *pixmin,int *pixmax) { struct vertex_list *v,*v1; - float xmax,xmin,nxmax; + float xmax,xmin,nxmax,rxmax,yl,xl; int fill=0,i; int ixmin,ixmax; xmin=1e10; xmax=-1e10; + rxmax=0; - v=vertices; + v=*vertices; while (v) { v->xmin=vertex_xmin(v,yp,&v->yxmin); @@ -418,10 +460,13 @@ static void polygone_row(struct image *img, *pixmin=ixmin=floor(xmin); *pixmax=ixmax=ceil(xmax); + rxmax=xmax; + if (rxmax>img->xsize) rxmax=img->xsize; + if (ixmin<0) { *pixmin=ixmin=xmin=0; - v=vertices; + v=*vertices; while (v) { if (v->xmin<0 && v->yxmin==yp) fill=!fill; @@ -435,11 +480,11 @@ static void polygone_row(struct image *img, for (i=ixmin; i<=ixmax; i++) buf[i]=0.0; - v=vertices; + v=*vertices; nxmax=xmax=v->xmax; v1=v; - v1=v=vertices; + v1=v=*vertices; #ifdef POLYDEBUG while (v) @@ -449,7 +494,7 @@ static void polygone_row(struct image *img, v->xmin,v->yxmin, v->xmax,v->yxmax),v=v->next; - v=vertices; + v=*vertices; #endif for (;;) @@ -459,16 +504,13 @@ static void polygone_row(struct image *img, xmin,xmax,nxmax); #endif - /* skip uninteresting, ends < v->xmin */ - while (v1 && v1->xmax<xmin) v1=v1->next; - if (!v1) break; - + if (!v1) break; /* sanity check */ + /* get next start or end */ v=v1; nxmax=0; - xmax=1e10; - /* known: v->xmin>=xmin */ + xmax=v->xmax; while (v) { #ifdef POLYDEBUG @@ -478,48 +520,125 @@ static void polygone_row(struct image *img, v->xmin,v->yxmin, v->xmax,v->yxmax,xmin,xmax,nxmax); #endif - if (v->xmin>xmin && v->xmin<xmax) xmax=v->xmin; - if (v->xmax>xmin && v->xmax<xmax) xmax=v->xmax; - if (v->xmax>nxmax) nxmax=v->xmax; - + if (v->xmin>xmin && v->xmin<xmax) + xmax=v->xmin; + if (v->xmax>xmin && v->xmax<xmax) + xmax=v->xmax; + if (v->xmin<=xmax && v->xmax>nxmax) nxmax=v->xmax; #ifdef POLYDEBUG fprintf(stderr,"xmin=%g xmax=%g nxmax=%g\n", - xmin,xmax,nxmax); + xmin,xmax,nxmax); #endif v=v->next; } - - if (xmax>nxmax) xmax=nxmax; - if (xmin>xmax) xmax=xmin; + +#ifdef POLYDEBUG + fprintf(stderr," xmax=%g nxmax=%g xmin=%g xmax=%g ixmax=%d fill=%d\n", + xmax,nxmax,xmin,xmax,ixmax,fill); +#endif + if (xmax>ixmax) xmax=ixmax; - - if (xmin==nxmax) break; - fill=polygone_row_vertices(buf,v1,v,xmin,xmax,yp,fill); +#ifdef POLYDEBUG + fprintf(stderr,"--> xmax=%g nxmax=%g xmin=%g xmax=%g ixmax=%d fill=%d\n", + xmax,nxmax,xmin,xmax,ixmax,fill); + + fprintf(stderr,"--- %g..%g --------------------------------------\n", + xmin,xmax); +#endif - if ((xmin=xmax)>=ixmax) break; + /* sort sanity check (needed, since sort is based on one line) */ - while (v1 && v1->xmax<xmin) v1=v1->next; - if (!v1) break; - v=vertices; - while (v) + v=v1; + yl=0; + xl=0; + while (v) { - if (v->xmax==xmax && v->yxmax==yp) fill=!fill; + if (v->xmax>=xmin && v->xmin<=xmin) + { + float y=VY(v,xmin); + if (y<yl) + { +resort: + /* resort */ +#ifdef POLYDEBUG + fprintf(stderr,"!!! resort !!!\n"); +#endif + v1=NULL; + add_vertices(&v1,*vertices,yp); + + while ((v=*vertices)) + { + *vertices=v->next; + free(v); + } + + *vertices=v1; + + /* forget the already done stuff */ + + while (v1 && v1->xmax<xmin) v1=v1->next; + + break; + } + yl=y; + } + if (xl>v->xmax) goto resort; + xl=v->xmin; v=v->next; } + + if (xmin!=nxmax) + polygone_row_vertices(buf,v1,v,xmin,xmax,yp,fill); - if (v && xmax==nxmax && v->xmin>nxmax) /* jump */ + fill=toggle_fill(v1,xmin,xmax,yp,fill); + +#ifdef POLYEDEBUG + fprintf(stderr,"v1=%lx xmax=%g nxmax=%g xmax==nxmax:%d\n", + (unsigned long)v1,xmax,nxmax,xmax==nxmax); +#endif + + /* skip uninteresting, ends < v->xmin */ + while (v1 && v1->xmax<=xmax && v1->xmin<xmax) v1=v1->next; + if (!v1) break; + + if (v1 && xmax==nxmax && xmax<rxmax) /* jump */ { - xmin=v->xmin; - if (nxmax>=ixmax) break; + float xminf=rxmax; + v=v1; + while (v) + { + if (v->xmax>nxmax && v->xmin<xminf) xminf=v->xmin; + v=v->next; + } + if (xmin!=xmax) fill=toggle_fill(v1,xmax,xminf,yp,fill); +#ifdef POLYDEBUG + fprintf(stderr,"aa jump %g..%g fill %d\n", + nxmax,xminf,fill); +#endif if (fill) - if (v->xmin>ixmax) - polygone_row_fill(buf,nxmax,ixmax); - else - polygone_row_fill(buf,nxmax,v->xmin); + polygone_row_fill(buf,xmax,xminf); + if (xminf==ixmax) break; + + xmin=xminf; } + else xmin=xmax; + + if (xmin>=rxmax) break; + + /* skip uninteresting, ends < v->xmin */ + while (v1 && v1->xmax==xmax) v1=v1->next; + if (!v1) break; + + } + +#ifdef POLYDEBUG + fprintf(stderr,"== "); + for (i=0; i<10; i++) fprintf(stderr,"%5.3f,",buf[i]); + fprintf(stderr,"\n"); +#endif } static void polygone_some(struct image *img, @@ -530,13 +649,24 @@ static void polygone_some(struct image *img, float yp; int i; - rgb_group *dest=img->img,rgb=img->rgb; float *buf=alloca(sizeof(float)*(img->xsize+1)); + if (!buf) error("out of stack, typ\n"); for (i=0; i<img->xsize+1; i++) buf[i]=0.0; + +#ifdef POLYDEBUG + next=top; + while (next) + { + fprintf(stderr,"%lx %g,%g\n",(unsigned long)next,next->x,next->y); + next=next->next; + } +#endif + + nextb=next=top; yp=floor(top->y); @@ -547,12 +677,13 @@ static void polygone_some(struct image *img, while (next) { #ifdef POLYDEBUG + struct vertex_list *v1; fprintf(stderr,"\n\nrow y=%g..%g\n",yp,yp+1); #endif /* add new vertices if any */ - while (next && next->y<=yp+1.0) + while (next && next->y<=yp+1.0-1e-10) { add_vertices(&vertices,next->below,yp); next=next->next; @@ -589,14 +720,13 @@ fprintf(stderr,"\n\nrow y=%g..%g\n",yp,yp+1); { int xmin,xmax; - polygone_row(img, buf, vertices,yp, &xmin,&xmax); + polygone_row(img, buf, &vertices,yp, &xmin,&xmax); -#if POLYDEBUG +#ifdef POLYDEBUG fprintf(stderr,"yp=%g dest=&%lx (&%lx..&%lx) xmin=%d xmax=%d; ", yp,(int)dest,(int)img->img, (int)img->img+img->xsize*img->ysize, xmin,xmax); - for (i=xmin; i<xmax; i++) fprintf(stderr,"%5.3f,",buf[i]); fprintf(stderr,"\n"); #endif @@ -609,13 +739,13 @@ fprintf(stderr,"\n\nrow y=%g..%g\n",yp,yp+1); /* remove done vertices if any */ - yp+=1.0; - - while (nextb && nextb->y<=yp) + while (nextb && nextb->y<yp+1.0-1e-10) { sub_vertices(&vertices,nextb,yp); nextb=nextb->next; } + + yp+=1.0; } }