static void plccal(PLFLT (*f2eval) (PLINT, PLINT, PLPointer), PLPointer f2eval_data, PLFLT flev, PLINT ix, PLINT iy, PLINT ixg, PLINT iyg, PLFLT *dist) { PLINT ia, ib; PLFLT dbot, dtop, fmid; PLFLT fxy, fab, fay, fxb, flow; ia = ix + ixg; ib = iy + iyg; fxy = f2eval(ix, iy, f2eval_data); fab = f2eval(ia, ib, f2eval_data); fxb = f2eval(ix, ib, f2eval_data); fay = f2eval(ia, iy, f2eval_data); if (ixg == 0 || iyg == 0) { dtop = flev - fxy; dbot = fab - fxy; *dist = 0.0; if (dbot != 0.0) *dist = dtop / dbot; } else { fmid = (fxy + fab + fxb + fay) / 4.0; *dist = 0.5; if ((fxy - flev) * (fab - flev) <= 0.) { if (fmid >= flev) { dtop = flev - fxy; dbot = fmid - fxy; if (dbot != 0.0) *dist = 0.5 * dtop / dbot; } else { dtop = flev - fab; dbot = fmid - fab; if (dbot != 0.0) *dist = 1.0 - 0.5 * dtop / dbot; } } else { flow = (fxb + fay) / 2.0; dtop = fab - flev; dbot = fab + fxy - 2.0 * flow; if (dbot != 0.0) *dist = 1. - dtop / dbot; } } if (*dist > 1.) *dist = 1.; }
static void pldrawcn(PLFLT (*f2eval) (PLINT, PLINT, PLPointer), PLPointer f2eval_data, PLINT nx, PLINT ny, PLINT kx, PLINT lx, PLINT ky, PLINT ly, PLFLT flev, char *flabel, PLINT kcol, PLINT krow, PLFLT lastx, PLFLT lasty, PLINT startedge, PLINT **ipts, PLFLT *distance, PLINT *lastindex, void (*pltr) (PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer), PLPointer pltr_data) { PLFLT f[4]; PLFLT px[4], py[4], locx[4], locy[4]; PLINT iedge[4]; PLINT i, j, k, num, first, inext, kcolnext, krownext; (*pltr) (kcol,krow+1,&px[0],&py[0],pltr_data); (*pltr) (kcol,krow,&px[1],&py[1],pltr_data); (*pltr) (kcol+1,krow,&px[2],&py[2],pltr_data); (*pltr) (kcol+1,krow+1,&px[3],&py[3],pltr_data); f[0] = f2eval(kcol, krow+1, f2eval_data)-flev; f[1] = f2eval(kcol, krow, f2eval_data)-flev; f[2] = f2eval(kcol+1, krow, f2eval_data)-flev; f[3] = f2eval(kcol+1, krow+1, f2eval_data)-flev; for (i=0,j=1;i<4;i++,j = (j+1)%4) { iedge[i] = (f[i]*f[j]>0.0)?-1:((f[i]*f[j] < 0.0)?1:0); } /* Mark this square as done */ ipts[kcol][krow] = 1; /* Check if no contour has been crossed i.e. iedge[i] = -1 */ if ((iedge[0] == -1) && (iedge[1] == -1) && (iedge[2] == -1) && (iedge[3] == -1)) return; /* Check if this is a completely flat square - in which case ignore it */ if ( (f[0] == 0.0) && (f[1] == 0.0) && (f[2] == 0.0) && (f[3] == 0.0) ) return; /* Calculate intersection points */ num = 0; if (startedge < 0) { first = 1; } else { locx[num] = lastx; locy[num] = lasty; num++; first = 0; } for (k=0, i = (startedge<0?0:startedge);k<4;k++,i=(i+1)%4) { if (i == startedge) continue; /* If the contour is an edge check it hasn't already been done */ if (f[i] == 0.0 && f[(i+1)%4] == 0.0) { kcolnext = kcol; krownext = krow; if (i == 0) kcolnext--; if (i == 1) krownext--; if (i == 2) kcolnext++; if (i == 3) krownext++; if ((kcolnext < kx) || (kcolnext >= lx) || (krownext < ky) || (krownext >= ly) || (ipts[kcolnext][krownext] == 1)) continue; } if ((iedge[i] == 1) || (f[i] == 0.0)) { j = (i+1)%4; if (f[i] != 0.0) { locx[num] = (px[i]*fabs(f[j])+px[j]*fabs(f[i]))/fabs(f[j]-f[i]); locy[num] = (py[i]*fabs(f[j])+py[j]*fabs(f[i]))/fabs(f[j]-f[i]); } else { locx[num] = px[i]; locy[num] = py[i]; } /* If this is the start of the contour then move to the point */ if (first == 1) { cont_mv_store(locx[num],locy[num]); first = 0; *distance = 0; *lastindex = 0; } else { /* Link to the next point on the contour */ if (contlabel_active) pl_drawcontlabel(locx[num], locy[num], flabel, distance, lastindex); else cont_xy_store(locx[num],locy[num]); /* Need to follow contour into next grid box */ /* Easy case where contour does not pass through corner */ if (f[i] != 0.0) { kcolnext = kcol; krownext = krow; inext = (i+2)%4; if (i == 0) kcolnext--; if (i == 1) krownext--; if (i == 2) kcolnext++; if (i == 3) krownext++; if ((kcolnext >= kx) && (kcolnext < lx) && (krownext >= ky) && (krownext < ly) && (ipts[kcolnext][krownext] == 0)) { pldrawcn(f2eval, f2eval_data, nx, ny, kx, lx, ky, ly, flev, flabel, kcolnext, krownext, locx[num], locy[num], inext, ipts, distance, lastindex, pltr, pltr_data); } } /* Hard case where contour passes through corner */ /* This is still not perfect - it may lose the contour * which won't upset the contour itself (we can find it * again later) but might upset the labelling */ else { kcolnext = kcol; krownext = krow; inext = (i+2)%4; if (i == 0) {kcolnext--; krownext++;} if (i == 1) {krownext--; kcolnext--;} if (i == 2) {kcolnext++; krownext--;} if (i == 3) {krownext++; kcolnext++;} if ((kcolnext >= kx) && (kcolnext < lx) && (krownext >= ky) && (krownext < ly) && (ipts[kcolnext][krownext] == 0)) { pldrawcn(f2eval, f2eval_data, nx, ny, kx, lx, ky, ly, flev, flabel, kcolnext, krownext, locx[num], locy[num], inext, ipts, distance, lastindex, pltr, pltr_data); } } if (first == 1) { /* Move back to first point */ cont_mv_store(locx[num],locy[num]); first = 0; *distance = 0; *lastindex = 0; first = 0; } else { first = 1; } num++; } } } }
static void plshade_int( PLFLT ( *f2eval )( PLINT, PLINT, PLPointer ), PLPointer f2eval_data, PLFLT ( * c2eval )( PLINT, PLINT, PLPointer ), // unused, but macro doesn't work PLPointer PL_UNUSED( c2eval_data ), PLINT ( *defined )( PLFLT, PLFLT ), PLINT nx, PLINT ny, PLFLT xmin, PLFLT xmax, PLFLT ymin, PLFLT ymax, PLFLT shade_min, PLFLT shade_max, PLINT sh_cmap, PLFLT sh_color, PLFLT sh_width, PLINT min_color, PLFLT min_width, PLINT max_color, PLFLT max_width, void ( *fill )( PLINT, const PLFLT *, const PLFLT * ), PLINT rectangular, void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ), PLPointer pltr_data ) { PLINT n, slope = 0, ix, iy; int count, i, j, nxny; PLFLT *a, *a0, *a1, dx, dy; PLFLT x[8], y[8], xp[2], tx, ty, init_width; int *c, *c0, *c1; (void) c2eval; // Cast to void to silence compiler warning about unused parameter if ( plsc->level < 3 ) { plabort( "plfshade: window must be set up first" ); return; } if ( nx <= 0 || ny <= 0 ) { plabort( "plfshade: nx and ny must be positive" ); return; } if ( shade_min >= shade_max ) { plabort( "plfshade: shade_max must exceed shade_min" ); return; } if ( pltr == NULL && plsc->coordinate_transform == NULL ) rectangular = 1; int_val = shade_max - shade_min; init_width = plsc->width; pen_col_min = min_color; pen_col_max = max_color; pen_wd_min = min_width; pen_wd_max = max_width; plstyl( (PLINT) 0, NULL, NULL ); plwidth( sh_width ); if ( fill != NULL ) { switch ( sh_cmap ) { case 0: plcol0( (PLINT) sh_color ); break; case 1: plcol1( sh_color ); break; default: plabort( "plfshade: invalid color map selection" ); return; } } // alloc space for value array, and initialize // This is only a temporary kludge nxny = nx * ny; if ( ( a = (PLFLT *) malloc( (size_t) nxny * sizeof ( PLFLT ) ) ) == NULL ) { plabort( "plfshade: unable to allocate memory for value array" ); return; } for ( ix = 0; ix < nx; ix++ ) for ( iy = 0; iy < ny; iy++ ) a[iy + ix * ny] = f2eval( ix, iy, f2eval_data ); // alloc space for condition codes if ( ( c = (int *) malloc( (size_t) nxny * sizeof ( int ) ) ) == NULL ) { plabort( "plfshade: unable to allocate memory for condition codes" ); free( a ); return; } sh_min = shade_min; sh_max = shade_max; set_cond( c, a, nxny ); dx = ( xmax - xmin ) / ( nx - 1 ); dy = ( ymax - ymin ) / ( ny - 1 ); a0 = a; a1 = a + ny; c0 = c; c1 = c + ny; for ( ix = 0; ix < nx - 1; ix++ ) { for ( iy = 0; iy < ny - 1; iy++ ) { count = c0[iy] + c0[iy + 1] + c1[iy] + c1[iy + 1]; // No filling needs to be done for these cases if ( count >= UNDEF ) continue; if ( count == 4 * POS ) continue; if ( count == 4 * NEG ) continue; // Entire rectangle can be filled if ( count == 4 * OK ) { // find biggest rectangle that fits if ( rectangular ) { big_recl( c0 + iy, ny, nx - ix, ny - iy, &i, &j ); } else { i = j = 1; } x[0] = x[1] = ix; x[2] = x[3] = ix + i; y[0] = y[3] = iy; y[1] = y[2] = iy + j; if ( pltr ) { for ( i = 0; i < 4; i++ ) { ( *pltr )( x[i], y[i], &tx, &ty, pltr_data ); x[i] = tx; y[i] = ty; } } else { for ( i = 0; i < 4; i++ ) { x[i] = xmin + x[i] * dx; y[i] = ymin + y[i] * dy; } } if ( fill != NULL ) exfill( fill, defined, (PLINT) 4, x, y ); iy += j - 1; continue; } // Only part of rectangle can be filled n_point = min_points = max_points = 0; n = find_interval( a0[iy], a0[iy + 1], c0[iy], c0[iy + 1], xp ); for ( j = 0; j < n; j++ ) { x[j] = ix; y[j] = iy + xp[j]; } i = find_interval( a0[iy + 1], a1[iy + 1], c0[iy + 1], c1[iy + 1], xp ); for ( j = 0; j < i; j++ ) { x[j + n] = ix + xp[j]; y[j + n] = iy + 1; } n += i; i = find_interval( a1[iy + 1], a1[iy], c1[iy + 1], c1[iy], xp ); for ( j = 0; j < i; j++ ) { x[n + j] = ix + 1; y[n + j] = iy + 1 - xp[j]; } n += i; i = find_interval( a1[iy], a0[iy], c1[iy], c0[iy], xp ); for ( j = 0; j < i; j++ ) { x[n + j] = ix + 1 - xp[j]; y[n + j] = iy; } n += i; if ( pltr ) { for ( i = 0; i < n; i++ ) { ( *pltr )( x[i], y[i], &tx, &ty, pltr_data ); x[i] = tx; y[i] = ty; } } else { for ( i = 0; i < n; i++ ) { x[i] = xmin + x[i] * dx; y[i] = ymin + y[i] * dy; } } if ( min_points == 4 ) slope = plctestez( a, nx, ny, ix, iy, shade_min ); if ( max_points == 4 ) slope = plctestez( a, nx, ny, ix, iy, shade_max ); // n = number of end of line segments // min_points = number times shade_min meets edge // max_points = number times shade_max meets edge // special cases: check number of times a contour is in a box switch ( ( min_points << 3 ) + max_points ) { case 000: case 020: case 002: case 022: if ( fill != NULL && n > 0 ) exfill( fill, defined, n, x, y ); break; case 040: // 2 contour lines in box case 004: if ( n != 6 ) fprintf( stderr, "plfshade err n=%d !6", (int) n ); if ( slope == 1 && c0[iy] == OK ) { if ( fill != NULL ) exfill( fill, defined, n, x, y ); } else if ( slope == 1 ) { selected_polygon( fill, defined, x, y, 0, 1, 2, -1 ); selected_polygon( fill, defined, x, y, 3, 4, 5, -1 ); } else if ( c0[iy + 1] == OK ) { if ( fill != NULL ) exfill( fill, defined, n, x, y ); } else { selected_polygon( fill, defined, x, y, 0, 1, 5, -1 ); selected_polygon( fill, defined, x, y, 2, 3, 4, -1 ); } break; case 044: if ( n != 8 ) fprintf( stderr, "plfshade err n=%d !8", (int) n ); if ( slope == 1 ) { selected_polygon( fill, defined, x, y, 0, 1, 2, 3 ); selected_polygon( fill, defined, x, y, 4, 5, 6, 7 ); } else { selected_polygon( fill, defined, x, y, 0, 1, 6, 7 ); selected_polygon( fill, defined, x, y, 2, 3, 4, 5 ); } break; case 024: case 042: // 3 contours if ( n != 7 ) fprintf( stderr, "plfshade err n=%d !7", (int) n ); if ( ( c0[iy] == OK || c1[iy + 1] == OK ) && slope == 1 ) { if ( fill != NULL ) exfill( fill, defined, n, x, y ); } else if ( ( c0[iy + 1] == OK || c1[iy] == OK ) && slope == 0 ) { if ( fill != NULL ) exfill( fill, defined, n, x, y ); } else if ( c0[iy] == OK ) { selected_polygon( fill, defined, x, y, 0, 1, 6, -1 ); selected_polygon( fill, defined, x, y, 2, 3, 4, 5 ); } else if ( c0[iy + 1] == OK ) { selected_polygon( fill, defined, x, y, 0, 1, 2, -1 ); selected_polygon( fill, defined, x, y, 3, 4, 5, 6 ); } else if ( c1[iy + 1] == OK ) { selected_polygon( fill, defined, x, y, 0, 1, 5, 6 ); selected_polygon( fill, defined, x, y, 2, 3, 4, -1 ); } else if ( c1[iy] == OK ) { selected_polygon( fill, defined, x, y, 0, 1, 2, 3 ); selected_polygon( fill, defined, x, y, 4, 5, 6, -1 ); } else { fprintf( stderr, "plfshade err logic case 024:042\n" ); } break; default: fprintf( stderr, "prog err switch\n" ); break; } draw_boundary( slope, x, y ); if ( fill != NULL ) { plwidth( sh_width ); if ( sh_cmap == 0 ) plcol0( (PLINT) sh_color ); else if ( sh_cmap == 1 ) plcol1( sh_color ); } } a0 = a1; c0 = c1; a1 += ny; c1 += ny; } free( c ); free( a ); plwidth( init_width ); }
static void pldrawcn(PLFLT (*f2eval) (PLINT, PLINT, PLPointer), PLPointer f2eval_data, PLINT nx, PLINT ny, PLINT kx, PLINT lx, PLINT ky, PLINT ly, PLFLT flev, char *flabel, PLINT kcol, PLINT krow, PLINT *p_kscan, PLINT *p_kstor, PLINT *iscan, PLINT *ixstor, PLINT *iystor, PLINT nstor, void (*pltr) (PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer), PLPointer pltr_data) { PLINT iwbeg, ixbeg, iybeg, izbeg; PLINT iboun, iw, ix, iy, iz, ifirst, istep, ixgo, iygo; PLINT l, ixg, iyg, ia, ib; PLFLT dist, dx, dy, xnew, ynew, fxl, fxr; PLFLT xlas = 0., ylas = 0., tpx, tpy, xt, yt; PLFLT f1, f2, f3, f4, fcheck; PLINT lastindex = 0; PLFLT distance = 0.0; /* Check if a contour has been crossed */ fxl = f2eval(kcol-1, krow, f2eval_data); fxr = f2eval(kcol, krow, f2eval_data); if (fxl < flev && fxr >= flev) { ixbeg = kcol - 1; iwbeg = kcol; } else if (fxr < flev && fxl > flev) { ixbeg = kcol; iwbeg = kcol - 1; } else return; iybeg = krow; izbeg = krow; /* A contour has been crossed. */ /* Check to see if it is a new one. */ for (l = 0; l < *p_kscan; l++) { if (ixbeg == iscan[l]) return; } for (iboun = 1; iboun >= -1; iboun -= 2) { /* Set up starting point and initial search directions */ ix = ixbeg; iy = iybeg; iw = iwbeg; iz = izbeg; ifirst = 1; istep = 0; ixgo = iw - ix; iygo = iz - iy; for (;;) { plccal(f2eval, f2eval_data, flev, ix, iy, ixgo, iygo, &dist); dx = dist * ixgo; dy = dist * iygo; xnew = ix + dx; ynew = iy + dy; /* Has a step occured in search? */ if (istep != 0) { if (ixgo * iygo == 0) { /* This was a diagonal step, so interpolate missed point. */ /* Rotating 45 degrees to get it */ ixg = ixgo; iyg = iygo; plr45(&ixg, &iyg, iboun); ia = iw - ixg; ib = iz - iyg; plccal(f2eval, f2eval_data, flev, ia, ib, ixg, iyg, &dist); (*pltr) (xlas, ylas, &tpx, &tpy, pltr_data); if (contlabel_active) pl_drawcontlabel(tpx, tpy, flabel, &distance, &lastindex); else cont_xy_store(tpx,tpy); /* plP_drawor(tpx, tpy); */ dx = dist * ixg; dy = dist * iyg; xlas = ia + dx; ylas = ib + dy; } else { if (dist > 0.5) { xt = xlas; xlas = xnew; xnew = xt; yt = ylas; ylas = ynew; ynew = yt; } } } if (ifirst != 1) { (*pltr) (xlas, ylas, &tpx, &tpy, pltr_data); if (contlabel_active) pl_drawcontlabel(tpx, tpy, flabel, &distance, &lastindex); else cont_xy_store(tpx,tpy); /* plP_drawor(tpx, tpy); */ } else { (*pltr) (xnew, ynew, &tpx, &tpy, pltr_data); cont_mv_store(tpx,tpy); /* plP_movwor(tpx, tpy); */ } xlas = xnew; ylas = ynew; /* Check if the contour is closed */ if (ifirst != 1 && ix == ixbeg && iy == iybeg && iw == iwbeg && iz == izbeg) { (*pltr) (xlas, ylas, &tpx, &tpy, pltr_data); if (contlabel_active) pl_drawcontlabel(tpx, tpy, flabel, &distance, &lastindex); else cont_xy_store(tpx,tpy); /* plP_drawor(tpx, tpy); */ return; } ifirst = 0; /* Now the rotation */ istep = 0; plr45(&ixgo, &iygo, iboun); iw = ix + ixgo; iz = iy + iygo; /* Check if out of bounds */ if (iw < kx || iw > lx || iz < ky || iz > ly) break; /* Has contact been lost with the contour? */ if (ixgo * iygo == 0) fcheck = f2eval(iw, iz, f2eval_data); else { f1 = f2eval(ix, iy, f2eval_data); f2 = f2eval(iw, iz, f2eval_data); f3 = f2eval(ix, iz, f2eval_data); f4 = f2eval(iw, iy, f2eval_data); fcheck = MAX(f2, (f1 + f2 + f3 + f4) / 4.); } if (fcheck < flev) { /* Yes, lost contact => step to new center */ istep = 1; ix = iw; iy = iz; plr135(&ixgo, &iygo, iboun); iw = ix + ixgo; iz = iy + iygo; /* And do the contour memory */ if (iy == krow) { *p_kscan = *p_kscan + 1; iscan[*p_kscan - 1] = ix; } else if (iy > krow) { *p_kstor = *p_kstor + 1; if (*p_kstor > nstor) { plabort("plfcont: heap exhausted"); error = 1; return; } ixstor[*p_kstor - 1] = ix; iystor[*p_kstor - 1] = iy; } } } /* Reach here only if boundary encountered - Draw last bit */ (*pltr) (xnew, ynew, &tpx, &tpy, pltr_data); /* distance = 0.0; */ cont_xy_store(tpx,tpy); /* plP_drawor(tpx, tpy); */ } }