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 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); */ } }