--- ray/src/common/image.c 2018/04/27 05:00:29 2.46 +++ ray/src/common/image.c 2025/06/25 15:28:56 2.58 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: image.c,v 2.46 2018/04/27 05:00:29 greg Exp $"; +static const char RCSid[] = "$Id: image.c,v 2.58 2025/06/25 15:28:56 greg Exp $"; #endif /* * image.c - routines for image generation. @@ -15,11 +15,6 @@ static const char RCSid[] = "$Id: image.c,v 2.46 2018/ #include "paths.h" #include "view.h" - -#define FEQ(x,y) (fabs((x)-(y)) <= FTINY) -#define VEQ(v,w) (FEQ((v)[0],(w)[0]) && FEQ((v)[1],(w)[1]) \ - && FEQ((v)[2],(w)[2])) - VIEW stdview = STDVIEW; /* default view parameters */ static gethfunc gethview; @@ -68,8 +63,8 @@ VIEW *v return(ill_horiz); if (v->vert >= 180.0-FTINY) return(ill_vert); - v->hn2 = 2.0 * tan(v->horiz*(PI/180.0/2.0)); - v->vn2 = 2.0 * tan(v->vert*(PI/180.0/2.0)); + v->hn2 = 2.0 * tan(v->horiz*(PI/360.)); + v->vn2 = 2.0 * tan(v->vert*(PI/360.)); break; case VT_CYL: /* cylindrical panorama */ if (v->horiz > 360.0+FTINY) @@ -77,7 +72,7 @@ VIEW *v if (v->vert >= 180.0-FTINY) return(ill_vert); v->hn2 = v->horiz * (PI/180.0); - v->vn2 = 2.0 * tan(v->vert*(PI/180.0/2.0)); + v->vn2 = 2.0 * tan(v->vert*(PI/360.)); break; case VT_ANG: /* angular fisheye */ if (v->horiz > 360.0+FTINY) @@ -92,18 +87,18 @@ VIEW *v return(ill_horiz); if (v->vert > 180.0+FTINY) return(ill_vert); - v->hn2 = 2.0 * sin(v->horiz*(PI/180.0/2.0)); - v->vn2 = 2.0 * sin(v->vert*(PI/180.0/2.0)); + v->hn2 = 2.0 * sin(v->horiz*(PI/360.)); + v->vn2 = 2.0 * sin(v->vert*(PI/360.)); break; case VT_PLS: /* planispheric fisheye */ if (v->horiz >= 360.0-FTINY) return(ill_horiz); if (v->vert >= 360.0-FTINY) return(ill_vert); - v->hn2 = 2.*sin(v->horiz*(PI/180.0/2.0)) / - (1.0 + cos(v->horiz*(PI/180.0/2.0))); - v->vn2 = 2.*sin(v->vert*(PI/180.0/2.0)) / - (1.0 + cos(v->vert*(PI/180.0/2.0))); + v->hn2 = 2.*sin(v->horiz*(PI/360.)) / + (1.0 + cos(v->horiz*(PI/360.))); + v->vn2 = 2.*sin(v->vert*(PI/360.)) / + (1.0 + cos(v->vert*(PI/360.))); break; default: return("unknown view type"); @@ -125,6 +120,79 @@ VIEW *v } +char * +cropview( /* crop a view to the indicated bounds */ +VIEW *v, +double x0, +double y0, +double x1, +double y1 +) +{ + static char ill_hemi[] = "illegal crop for hemispherical view"; + double d; + /* order crop extrema */ + if (x0 > x1) { d=x0; x0=x1; x1=d; } + if (y0 > y1) { d=y0; y0=y1; y1=d; } + + if ((x1-x0 <= FTINY) | (y1-y0 <= FTINY)) + return("zero crop area"); + + d = x1 - x0; /* adjust horizontal size? */ + if (!FABSEQ(d, 1.)) + switch (v->type) { + case VT_PER: + v->horiz = 360./PI*atan( d*tan(PI/360.*v->horiz) ); + break; + case VT_PAR: + case VT_ANG: + case VT_CYL: + v->horiz *= d; + break; + case VT_HEM: + d *= sin(PI/360.*v->horiz); + if (d > 1.) + return(ill_hemi); + v->horiz = 360./PI*asin( d ); + break; + case VT_PLS: + d *= sin(PI/360.*v->horiz) / + (1. + cos(PI/360.*v->horiz)); + v->horiz = 360./PI*acos( (1. - d*d) / (1. + d*d) ); + break; + } + + d = y1 - y0; /* adjust vertical size? */ + if (!FABSEQ(d, 1.)) + switch (v->type) { + case VT_PER: + case VT_CYL: + v->vert = 360./PI*atan( d*tan(PI/360.*v->vert) ); + break; + case VT_PAR: + case VT_ANG: + v->vert *= d; + break; + case VT_HEM: + d *= sin(PI/360.*v->vert); + if (d > 1.) + return(ill_hemi); + v->vert = 360./PI*asin( d ); + break; + case VT_PLS: + d *= sin(PI/360.*v->vert) / + (1. + cos(PI/360.*v->vert)); + v->vert = 360./PI*acos( (1. - d*d) / (1. + d*d) ); + break; + } + /* adjust offsets */ + v->hoff = ((x0 + x1)*.5 - .5 + v->hoff) / (x1 - x0); + v->voff = ((y0 + y1)*.5 - .5 + v->voff) / (y1 - y0); + + return(setview(v)); /* final error checks & set-up */ +} + + void normaspect( /* fix pixel aspect or resolution */ double va, /* view aspect ratio */ @@ -245,8 +313,8 @@ FVECT p break; case VT_PER: /* perspective view */ d = DOT(disp,v->vdir); - if ((v->vaft > FTINY) & (d > v->vaft)) - rflags |= VL_BEYOND; + rflags |= VL_BEYOND*((v->vaft > FTINY) & + (d >= v->vaft)); ip[2] = VLEN(disp); if (d < -FTINY) { /* fold pyramid */ ip[2] = -ip[2]; @@ -272,12 +340,12 @@ FVECT p d = DOT(disp,v->hvec); d2 = DOT(disp,v->vdir); ip[0] = 180.0/PI * atan2(d,d2) / v->horiz + 0.5 - v->hoff; - d = d*d + d2*d2; - if (d <= FTINY*FTINY) + d2 = d*d + d2*d2; + if (d2 <= FTINY*FTINY) return(VL_BAD); /* at pole */ - if ((v->vaft > FTINY) & (d > v->vaft*v->vaft)) - rflags |= VL_BEYOND; - d = 1.0/sqrt(d); + rflags |= VL_BEYOND*((v->vaft > FTINY) & + (d2 >= v->vaft*v->vaft)); + d = 1.0/sqrt(d2); ip[1] = DOT(disp,v->vvec)*d/v->vn2 + 0.5 - v->voff; ip[2] = VLEN(disp); ip[2] *= (1.0 - v->vfore*d); @@ -315,11 +383,13 @@ FVECT p ip[0] = DOT(disp,v->hvec)/v->hn2 + 0.5 - v->hoff; ip[1] = DOT(disp,v->vvec)/v->vn2 + 0.5 - v->voff; gotall: /* add appropriate return flags */ - rflags |= VL_BEHIND*(ip[2] <= 0.0); + if (ip[2] <= 0.0) + rflags |= VL_BEHIND; + else if ((v->type != VT_PER) & (v->type != VT_CYL)) + rflags |= VL_BEYOND*((v->vaft > FTINY) & + (ip[2] >= v->vaft - v->vfore)); rflags |= VL_OUTSIDE*((0.0 >= ip[0]) | (ip[0] >= 1.0) | (0.0 >= ip[1]) | (ip[1] >= 1.0)); - if ((v->vaft > FTINY) & !(rflags & (VL_BEHIND|VL_BEYOND))) - rflags |= VL_BEYOND*(ip[2] > v->vaft - v->vfore); return(rflags); } @@ -384,14 +454,14 @@ int ac, char *av[] ) { -#define check(c,l) if ((av[0][c]&&av[0][c]!=' ') || \ +#define check(c,l) if ((av[0][c]&&!isspace(av[0][c])) || \ badarg(ac-1,av+1,l)) return(-1) if (ac <= 0 || av[0][0] != '-' || av[0][1] != 'v') return(-1); switch (av[0][2]) { case 't': /* type */ - if (!av[0][3] || av[0][3]==' ') + if (!av[0][3] || isspace(av[0][3])) return(-1); check(4,""); v->type = av[0][3]; @@ -488,14 +558,14 @@ FILE *fp ) { fprintf(fp, " -vt%c", vp->type); - fprintf(fp, " -vp %.6g %.6g %.6g", vp->vp[0], vp->vp[1], vp->vp[2]); - fprintf(fp, " -vd %.6g %.6g %.6g", vp->vdir[0]*vp->vdist, + fprintf(fp, " -vp %.7g %.7g %.7g", vp->vp[0], vp->vp[1], vp->vp[2]); + fprintf(fp, " -vd %.7g %.7g %.7g", vp->vdir[0]*vp->vdist, vp->vdir[1]*vp->vdist, vp->vdir[2]*vp->vdist); - fprintf(fp, " -vu %.6g %.6g %.6g", vp->vup[0], vp->vup[1], vp->vup[2]); - fprintf(fp, " -vh %.6g -vv %.6g", vp->horiz, vp->vert); - fprintf(fp, " -vo %.6g -va %.6g", vp->vfore, vp->vaft); - fprintf(fp, " -vs %.6g -vl %.6g", vp->hoff, vp->voff); + fprintf(fp, " -vu %.5g %.5g %.5g", vp->vup[0], vp->vup[1], vp->vup[2]); + fprintf(fp, " -vh %.5g -vv %.5g", vp->horiz, vp->vert); + fprintf(fp, " -vo %.5g -va %.5g", vp->vfore, vp->vaft); + fprintf(fp, " -vs %.5g -vl %.5g", vp->hoff, vp->voff); } @@ -512,44 +582,44 @@ VIEW *vp sprintf(cp, " -vt%c", vp->type); cp += strlen(cp); } - if (!VEQ(vp->vp,stdview.vp)) { + if (!VABSEQ(vp->vp,stdview.vp)) { sprintf(cp, " -vp %.6g %.6g %.6g", vp->vp[0], vp->vp[1], vp->vp[2]); cp += strlen(cp); } - if (!FEQ(vp->vdist,stdview.vdist) || !VEQ(vp->vdir,stdview.vdir)) { + if (!FABSEQ(vp->vdist,stdview.vdist) || !VABSEQ(vp->vdir,stdview.vdir)) { sprintf(cp, " -vd %.6g %.6g %.6g", vp->vdir[0]*vp->vdist, vp->vdir[1]*vp->vdist, vp->vdir[2]*vp->vdist); cp += strlen(cp); } - if (!VEQ(vp->vup,stdview.vup)) { + if (!VABSEQ(vp->vup,stdview.vup)) { sprintf(cp, " -vu %.6g %.6g %.6g", vp->vup[0], vp->vup[1], vp->vup[2]); cp += strlen(cp); } - if (!FEQ(vp->horiz,stdview.horiz)) { + if (!FABSEQ(vp->horiz,stdview.horiz)) { sprintf(cp, " -vh %.6g", vp->horiz); cp += strlen(cp); } - if (!FEQ(vp->vert,stdview.vert)) { + if (!FABSEQ(vp->vert,stdview.vert)) { sprintf(cp, " -vv %.6g", vp->vert); cp += strlen(cp); } - if (!FEQ(vp->vfore,stdview.vfore)) { + if (!FABSEQ(vp->vfore,stdview.vfore)) { sprintf(cp, " -vo %.6g", vp->vfore); cp += strlen(cp); } - if (!FEQ(vp->vaft,stdview.vaft)) { + if (!FABSEQ(vp->vaft,stdview.vaft)) { sprintf(cp, " -va %.6g", vp->vaft); cp += strlen(cp); } - if (!FEQ(vp->hoff,stdview.hoff)) { + if (!FABSEQ(vp->hoff,stdview.hoff)) { sprintf(cp, " -vs %.6g", vp->hoff); cp += strlen(cp); } - if (!FEQ(vp->voff,stdview.voff)) { + if (!FABSEQ(vp->voff,stdview.voff)) { sprintf(cp, " -vl %.6g", vp->voff); cp += strlen(cp); } @@ -562,8 +632,7 @@ isview( /* is this a view string? */ char *s ) { - static char *altname[]={NULL,VIEWSTR,"rpict","rview","rvu","rpiece","pinterp",NULL}; - extern char *progname; + static char *altname[]={NULL,VIEWSTR,"rpict","rvu","rpiece","rxpiece","pinterp","rview",NULL}; char *cp; char **an; /* add program name to list */ @@ -576,7 +645,7 @@ char *s } /* skip leading path */ cp = s; - while (*cp && *cp != ' ') + while (*cp && !isspace(*cp)) cp++; while (cp > s && !ISDIRSEP(cp[-1])) cp--; @@ -628,7 +697,8 @@ RESOLU *rp if (rp != NULL && !fgetsresolu(rp, fp)) mvs.ok = 0; - fclose(fp); + if (fp != stdin) + fclose(fp); return(mvs.ok); }