echoObject * echoRoughSphereNew(echoScene *scene, int theRes, int phiRes, echoPos_t *matx) { echoObject *trim; echoPos_t *_pos, *pos, tmp[3]; int *_vert, *vert, thidx, phidx, n; echoPos_t th, ph; trim = echoObjectNew(scene, echoTypeTriMesh); TRIMESH(trim)->numV = 2 + (phiRes-1)*theRes; TRIMESH(trim)->numF = (2 + 2*(phiRes-2))*theRes; _pos = pos = (echoPos_t *)calloc(3*TRIMESH(trim)->numV, sizeof(echoPos_t)); _vert = vert = (int *)calloc(3*TRIMESH(trim)->numF, sizeof(int)); ELL_3V_SET(tmp, 0, 0, 1); _echoPosSet(pos, matx, tmp); pos += 3; for (phidx=1; phidx<phiRes; phidx++) { ph = AIR_AFFINE(0, phidx, phiRes, 0.0, AIR_PI); for (thidx=0; thidx<theRes; thidx++) { th = AIR_AFFINE(0, thidx, theRes, 0.0, 2*AIR_PI); ELL_3V_SET(tmp, cos(th)*sin(ph), sin(th)*sin(ph), cos(ph)); _echoPosSet(pos, matx, tmp); pos += 3; } } ELL_3V_SET(tmp, 0, 0, -1); _echoPosSet(pos, matx, tmp); for (thidx=0; thidx<theRes; thidx++) { n = AIR_MOD(thidx+1, theRes); ELL_3V_SET(vert, 0, 1+thidx, 1+n); vert += 3; } for (phidx=0; phidx<phiRes-2; phidx++) { for (thidx=0; thidx<theRes; thidx++) { n = AIR_MOD(thidx+1, theRes); ELL_3V_SET(vert, 1+phidx*theRes+thidx, 1+(1+phidx)*theRes+thidx, 1+phidx*theRes+n); vert += 3; ELL_3V_SET(vert, 1+(1+phidx)*theRes+thidx, 1+(1+phidx)*theRes+n, 1+phidx*theRes+n); vert += 3; } } for (thidx=0; thidx<theRes; thidx++) { n = AIR_MOD(thidx+1, theRes); ELL_3V_SET(vert, 1+(phiRes-2)*theRes+thidx, TRIMESH(trim)->numV-1, 1+(phiRes-2)*theRes+n); vert += 3; } echoTriMeshSet(trim, TRIMESH(trim)->numV, _pos, TRIMESH(trim)->numF, _vert); return(trim); }
void _limnSplineIndexFind(int *idx, limnSpline *spline, int ii) { int N, ti[4]; N = spline->ncpt->axis[2].size; if (limnSplineTypeHasImplicitTangents[spline->type]) { if (spline->loop) { ELL_4V_SET(ti, AIR_MOD(ii-1, N), AIR_MOD(ii+0, N), AIR_MOD(ii+1, N), AIR_MOD(ii+2, N)); } else { ELL_4V_SET(ti, AIR_CLAMP(0, ii-1, N-1), AIR_CLAMP(0, ii+0, N-1), AIR_CLAMP(0, ii+1, N-1), AIR_CLAMP(0, ii+2, N-1)); } ELL_4V_SET(idx, 1 + 3*ti[0], 1 + 3*ti[1], 1 + 3*ti[2], 1 + 3*ti[3]); } else { if (spline->loop) { ELL_4V_SET(ti, AIR_MOD(ii+0, N), AIR_MOD(ii+0, N), AIR_MOD(ii+1, N), AIR_MOD(ii+1, N)); } else { ELL_4V_SET(ti, AIR_CLAMP(0, ii+0, N-1), AIR_CLAMP(0, ii+0, N-1), AIR_CLAMP(0, ii+1, N-1), AIR_CLAMP(0, ii+1, N-1)); } ELL_4V_SET(idx, 1 + 3*ti[0], 2 + 3*ti[1], 0 + 3*ti[2], 1 + 3*ti[3]); } }
/* ** _nrrdResampleMakeWeightIndex() ** ** _allocate_ and fill the arrays of indices and weights that are ** needed to process all the scanlines along a given axis; also ** be so kind as to set the sampling ratio (<1: downsampling, ** new sample spacing larger, >1: upsampling, new sample spacing smaller) ** ** returns "dotLen", the number of input samples which are required ** for resampling this axis, or 0 if there was an error. Uses biff. */ int _nrrdResampleMakeWeightIndex(nrrdResample_t **weightP, int **indexP, double *ratioP, const Nrrd *nin, const NrrdResampleInfo *info, unsigned int ai) { char me[]="_nrrdResampleMakeWeightIndex", err[BIFF_STRLEN]; int sizeIn, sizeOut, center, dotLen, halfLen, *index, base, idx; nrrdResample_t minIn, maxIn, minOut, maxOut, spcIn, spcOut, ratio, support, integral, pos, idxD, wght; nrrdResample_t *weight; double parm[NRRD_KERNEL_PARMS_NUM]; int e, i; if (!(info->kernel[ai])) { sprintf(err, "%s: don't see a kernel for dimension %d", me, ai); biffAdd(NRRD, err); *weightP = NULL; *indexP = NULL; return 0; } center = _nrrdCenter(nin->axis[ai].center); sizeIn = nin->axis[ai].size; sizeOut = info->samples[ai]; minIn = AIR_CAST(nrrdResample_t, nin->axis[ai].min); maxIn = AIR_CAST(nrrdResample_t, nin->axis[ai].max); minOut = AIR_CAST(nrrdResample_t, info->min[ai]); maxOut = AIR_CAST(nrrdResample_t, info->max[ai]); spcIn = NRRD_SPACING(center, minIn, maxIn, sizeIn); spcOut = NRRD_SPACING(center, minOut, maxOut, sizeOut); *ratioP = ratio = spcIn/spcOut; support = AIR_CAST(nrrdResample_t, info->kernel[ai]->support(info->parm[ai])); integral = AIR_CAST(nrrdResample_t, info->kernel[ai]->integral(info->parm[ai])); /* fprintf(stderr, "!%s(%d): size{In,Out} = %d, %d, support = %f; ratio = %f\n", me, d, sizeIn, sizeOut, support, ratio); */ if (ratio > 1) { /* if upsampling, we need only as many samples as needed for interpolation with the given kernel */ dotLen = (int)(2*ceil(support)); } else { /* if downsampling, we need to use all the samples covered by the stretched out version of the kernel */ if (info->cheap) { dotLen = (int)(2*ceil(support)); } else { dotLen = (int)(2*ceil(support/ratio)); } } /* fprintf(stderr, "!%s(%d): dotLen = %d\n", me, d, dotLen); */ weight = (nrrdResample_t*)calloc(sizeOut*dotLen, sizeof(nrrdResample_t)); index = (int*)calloc(sizeOut*dotLen, sizeof(int)); if (!(weight && index)) { sprintf(err, "%s: can't allocate weight and index arrays", me); biffAdd(NRRD, err); *weightP = NULL; *indexP = NULL; return 0; } /* calculate sample locations and do first pass on indices */ halfLen = dotLen/2; for (i=0; i<sizeOut; i++) { pos = AIR_CAST(nrrdResample_t, NRRD_POS(center, minOut, maxOut, sizeOut, i)); idxD = AIR_CAST(nrrdResample_t, NRRD_IDX(center, minIn, maxIn, sizeIn, pos)); base = (int)floor(idxD) - halfLen + 1; for (e=0; e<dotLen; e++) { index[e + dotLen*i] = base + e; weight[e + dotLen*i] = idxD - index[e + dotLen*i]; } /* ******** if (!i) { fprintf(stderr, "%s: sample locations:\n", me); } fprintf(stderr, "%s: %d (sample locations)\n ", me, i); for (e=0; e<dotLen; e++) { fprintf(stderr, "%d/%g ", index[e + dotLen*i], weight[e + dotLen*i]); } fprintf(stderr, "\n"); ******** */ } /* nrrdBoundaryPad, 1: fill with some user-specified value nrrdBoundaryBleed, 2: copy the last/first value out as needed nrrdBoundaryWrap, 3: wrap-around nrrdBoundaryWeight, 4: normalize the weighting on the existing samples; ONLY sensible for a strictly positive kernel which integrates to unity (as in blurring) */ /* figure out what to do with the out-of-range indices */ for (i=0; i<dotLen*sizeOut; i++) { idx = index[i]; if (!AIR_IN_CL(0, idx, sizeIn-1)) { switch(info->boundary) { case nrrdBoundaryPad: case nrrdBoundaryWeight: /* this will be further handled later */ idx = sizeIn; break; case nrrdBoundaryBleed: idx = AIR_CLAMP(0, idx, sizeIn-1); break; case nrrdBoundaryWrap: idx = AIR_MOD(idx, sizeIn); break; default: sprintf(err, "%s: boundary behavior %d unknown/unimplemented", me, info->boundary); biffAdd(NRRD, err); *weightP = NULL; *indexP = NULL; return 0; } index[i] = idx; } } /* run the sample locations through the chosen kernel. We play a sneaky trick on the kernel parameter 0 in case of downsampling to create the blurring of the old index space, but only if !cheap */ memcpy(parm, info->parm[ai], NRRD_KERNEL_PARMS_NUM*sizeof(double)); if (ratio < 1 && !(info->cheap)) { parm[0] /= ratio; } info->kernel[ai]->EVALN(weight, weight, dotLen*sizeOut, parm); /* ******** for (i=0; i<sizeOut; i++) { fprintf(stderr, "%s: %d (sample weights)\n ", me, i); for (e=0; e<dotLen; e++) { fprintf(stderr, "%d/%g ", index[e + dotLen*i], weight[e + dotLen*i]); } fprintf(stderr, "\n"); } ******** */ if (nrrdBoundaryWeight == info->boundary) { if (integral) { /* above, we set to sizeIn all the indices that were out of range. We now use that to determine the sum of the weights for the indices that were in-range */ for (i=0; i<sizeOut; i++) { wght = 0; for (e=0; e<dotLen; e++) { if (sizeIn != index[e + dotLen*i]) { wght += weight[e + dotLen*i]; } } for (e=0; e<dotLen; e++) { idx = index[e + dotLen*i]; if (sizeIn != idx) { weight[e + dotLen*i] *= integral/wght; } else { weight[e + dotLen*i] = 0; } } } } } else { /* try to remove ripple/grating on downsampling */ /* if (ratio < 1 && info->renormalize && integral) { */ if (info->renormalize && integral) { for (i=0; i<sizeOut; i++) { wght = 0; for (e=0; e<dotLen; e++) { wght += weight[e + dotLen*i]; } if (wght) { for (e=0; e<dotLen; e++) { /* this used to normalize the weights so that they summed to integral ("*= integral/wght"), which meant that if you use a very truncated Gaussian, then your over-all image brightness goes down. This seems very contrary to the whole point of renormalization. */ weight[e + dotLen*i] *= AIR_CAST(nrrdResample_t, 1.0/wght); } } } } } /* ******** fprintf(stderr, "%s: sample weights:\n", me); for (i=0; i<sizeOut; i++) { fprintf(stderr, "%s: %d\n ", me, i); wght = 0; for (e=0; e<dotLen; e++) { fprintf(stderr, "%d/%g ", index[e + dotLen*i], weight[e + dotLen*i]); wght += weight[e + dotLen*i]; } fprintf(stderr, " (sum = %g)\n", wght); } ******** */ *weightP = weight; *indexP = index; /* fprintf(stderr, "!%s: dotLen = %d\n", me, dotLen); */ return dotLen; }
/* ** _nrrdResampleComputePermute() ** ** figures out information related to how the axes in a nrrd are ** permuted during resampling: permute, topRax, botRax, passes, ax[][], sz[][] */ void _nrrdResampleComputePermute(unsigned int permute[], unsigned int ax[NRRD_DIM_MAX][NRRD_DIM_MAX], size_t sz[NRRD_DIM_MAX][NRRD_DIM_MAX], int *topRax, int *botRax, unsigned int *passes, const Nrrd *nin, const NrrdResampleInfo *info) { /* char me[]="_nrrdResampleComputePermute"; */ unsigned int bi, ai, pi; /* what are the first (top) and last (bottom) axes being resampled? */ *topRax = *botRax = -1; for (ai=0; ai<nin->dim; ai++) { if (info->kernel[ai]) { if (*topRax < 0) { *topRax = ai; } *botRax = ai; } } /* figure out total number of passes needed, and construct the permute[] array. permute[i] = j means that the axis in position i of the old array will be in position j of the new one (permute[] answers "where do I put this", not "what do I put here"). */ *passes = bi = 0; for (ai=0; ai<nin->dim; ai++) { if (info->kernel[ai]) { do { bi = AIR_MOD((int)bi+1, (int)nin->dim); /* HEY scrutinize casts */ } while (!info->kernel[bi]); permute[bi] = ai; *passes += 1; } else { permute[ai] = ai; bi += bi == ai; } } permute[nin->dim] = nin->dim; if (!*passes) { /* none of the kernels was non-NULL */ return; } /* fprintf(stderr, "%s: permute:\n", me); for (d=0; d<nin->dim; d++) { fprintf(stderr, " permute[%d] = %d\n", d, permute[ai]); } */ /* create array of how the axes will be arranged in each pass ("ax"), and create array of how big each axes is in each pass ("sz"). The input to pass i will have axis layout described in ax[i] and axis sizes described in sz[i] */ for (ai=0; ai<nin->dim; ai++) { ax[0][ai] = ai; sz[0][ai] = nin->axis[ai].size; } for (pi=0; pi<*passes; pi++) { for (ai=0; ai<nin->dim; ai++) { ax[pi+1][permute[ai]] = ax[pi][ai]; if (ai == (unsigned int)*topRax) { /* HEY scrutinize casts */ /* this is the axis which is getting resampled, so the number of samples is potentially changing */ sz[pi+1][permute[ai]] = (info->kernel[ax[pi][ai]] ? info->samples[ax[pi][ai]] : sz[pi][ai]); } else { /* this axis is just a shuffled version of the previous axis; no resampling this pass. Note: this case also includes axes which aren't getting resampled whatsoever */ sz[pi+1][permute[ai]] = sz[pi][ai]; } } } return; }
void * _alanTuringWorker(void *_task) { alan_t *tendata, *ten, react, conf, Dxx, Dxy, Dyy, /* Dxz, Dyz, */ *tpx, *tmx, *tpy, *tmy, /* *tpz, *tmz, */ *lev0, *lev1, *parm, deltaT, alpha, beta, A, B, *v[27], lapA, lapB, corrA, corrB, deltaA, deltaB, diffA, diffB, change; int dim, iter, stop, startW, endW, idx, px, mx, py, my, pz, mz, startY, endY, startZ, endZ, sx, sy, sz, x, y, z; alanTask *task; task = (alanTask *)_task; dim = task->actx->dim; sx = task->actx->size[0]; sy = task->actx->size[1]; sz = (2 == dim ? 1 : task->actx->size[2]); parm = (alan_t*)(task->actx->nparm->data); diffA = AIR_CAST(alan_t, task->actx->diffA/pow(task->actx->deltaX, dim)); diffB = AIR_CAST(alan_t, task->actx->diffB/pow(task->actx->deltaX, dim)); startW = task->idx*sy/task->actx->numThreads; endW = (task->idx+1)*sy/task->actx->numThreads; tendata = task->actx->nten ? (alan_t *)task->actx->nten->data : NULL; react = task->actx->react; if (2 == dim) { startZ = 0; endZ = 1; startY = startW; endY = endW; } else { startZ = startW; endZ = endW; startY = 0; endY = sy; } for (iter = 0; (alanStopNot == task->actx->stop && (0 == task->actx->maxIteration || iter < task->actx->maxIteration)); iter++) { if (0 == task->idx) { task->actx->iter = iter; task->actx->nlev = task->actx->_nlev[(iter+1) % 2]; } lev0 = (alan_t*)(task->actx->_nlev[iter % 2]->data); lev1 = (alan_t*)(task->actx->_nlev[(iter+1) % 2]->data); stop = alanStopNot; change = 0; conf = 1; /* if you have no data; this will stay 1 */ for (z = startZ; z < endZ; z++) { if (task->actx->wrap) { pz = AIR_MOD(z+1, sz); mz = AIR_MOD(z-1, sz); } else { pz = AIR_MIN(z+1, sz-1); mz = AIR_MAX(z-1, 0); } for (y = startY; y < endY; y++) { if (task->actx->wrap) { py = AIR_MOD(y+1, sy); my = AIR_MOD(y-1, sy); } else { py = AIR_MIN(y+1, sy-1); my = AIR_MAX(y-1, 0); } for (x = 0; x < sx; x++) { if (task->actx->wrap) { px = AIR_MOD(x+1, sx); mx = AIR_MOD(x-1, sx); } else { px = AIR_MIN(x+1, sx-1); mx = AIR_MAX(x-1, 0); } idx = x + sx*(y + sy*z); A = lev0[0 + 2*idx]; B = lev0[1 + 2*idx]; deltaT = parm[0 + 3*idx]; alpha = parm[1 + 3*idx]; beta = parm[2 + 3*idx]; lapA = lapB = corrA = corrB = 0; if (2 == dim) { /* ** 0 1 2 ----> X ** 3 4 5 ** 6 7 8 ** | ** v Y */ v[1] = lev0 + 2*( x + sx*(my)); v[3] = lev0 + 2*(mx + sx*( y)); v[5] = lev0 + 2*(px + sx*( y)); v[7] = lev0 + 2*( x + sx*(py)); if (tendata) { /* ** 0 1 2 Dxy/2 Dyy -Dxy/2 ** 3 4 5 Dxx -2*(Dxx + Dyy) Dxx ** 6 7 8 -Dxy/2 Dyy Dxy/2 */ v[0] = lev0 + 2*(mx + sx*(my)); v[2] = lev0 + 2*(px + sx*(my)); v[6] = lev0 + 2*(mx + sx*(py)); v[8] = lev0 + 2*(px + sx*(py)); ten = tendata + 4*idx; conf = AIR_CAST(alan_t, (AIR_CLAMP(0.3, ten[0], 1) - 0.3)/0.7); if (conf) { Dxx = ten[1]; Dxy = ten[2]; Dyy = ten[3]; lapA = (Dxy*(v[0][0] + v[8][0] - v[2][0] - v[6][0])/2 + Dxx*(v[3][0] + v[5][0]) + Dyy*(v[1][0] + v[7][0]) - 2*(Dxx + Dyy)*A); lapB = (Dxy*(v[0][1] + v[8][1] - v[2][1] - v[6][1])/2 + Dxx*(v[3][1] + v[5][1]) + Dyy*(v[1][1] + v[7][1]) - 2*(Dxx + Dyy)*B); if (!(task->actx->homogAniso)) { tpx = tendata + 4*(px + sx*( y + sy*( z))); tmx = tendata + 4*(mx + sx*( y + sy*( z))); tpy = tendata + 4*( x + sx*(py + sy*( z))); tmy = tendata + 4*( x + sx*(my + sy*( z))); corrA = ((tpx[1]-tmx[1])*(v[5][0]-v[3][0])/4+ /* Dxx,x*A,x */ (tpx[2]-tmx[2])*(v[7][0]-v[1][0])/4+ /* Dxy,x*A,y */ (tpy[2]-tmy[2])*(v[5][0]-v[3][0])/4+ /* Dxy,y*A,x */ (tpy[3]-tmy[3])*(v[7][0]-v[1][0])); /* Dyy,y*A,y */ corrB = ((tpx[1]-tmx[1])*(v[5][1]-v[3][1])/4+ /* Dxx,x*B,x */ (tpx[2]-tmx[2])*(v[7][1]-v[1][1])/4+ /* Dxy,x*B,y */ (tpy[2]-tmy[2])*(v[5][1]-v[3][1])/4+ /* Dxy,y*B,x */ (tpy[3]-tmy[3])*(v[7][1]-v[1][1])); /* Dyy,y*B,y */ } } else { /* no confidence; you diffuse */ lapA = v[1][0] + v[3][0] + v[5][0] + v[7][0] - 4*A; lapB = v[1][1] + v[3][1] + v[5][1] + v[7][1] - 4*B; } } else { /* no data; you diffuse */ lapA = v[1][0] + v[3][0] + v[5][0] + v[7][0] - 4*A; lapB = v[1][1] + v[3][1] + v[5][1] + v[7][1] - 4*B; } } else { /* 3 == dim */ /* ** 0 1 2 ---- X ** 3 4 5 ** 6 7 8 ** / ** / 9 10 11 ** Y 12 13 14 ** 15 16 17 ** ** 18 19 20 ** 21 22 23 ** 24 25 26 ** | ** | ** Z */ v[ 4] = lev0 + 2*( x + sx*( y + sy*(mz))); v[10] = lev0 + 2*( x + sx*(my + sy*( z))); v[12] = lev0 + 2*(mx + sx*( y + sy*( z))); v[14] = lev0 + 2*(px + sx*( y + sy*( z))); v[16] = lev0 + 2*( x + sx*(py + sy*( z))); v[22] = lev0 + 2*( x + sx*( y + sy*(pz))); if (tendata) { if (!(task->actx->homogAniso)) { } } else { lapA = (v[ 4][0] + v[10][0] + v[12][0] + v[14][0] + v[16][0] + v[22][0] - 6*A); lapB = (v[ 4][1] + v[10][1] + v[12][1] + v[14][1] + v[16][1] + v[22][1] - 6*B); } } deltaA = deltaT*(react*conf*task->actx->K*(alpha - A*B) + diffA*(lapA + corrA)); if (AIR_ABS(deltaA) > task->actx->maxPixelChange) { stop = alanStopDiverged; } change += AIR_ABS(deltaA); deltaB = deltaT*(react*conf*task->actx->K*(A*B - B - beta) + diffB*(lapB + corrB)); if (!( AIR_EXISTS(deltaA) && AIR_EXISTS(deltaB) )) { stop = alanStopNonExist; } A += deltaA; B = AIR_MAX(0, B + deltaB); lev1[0 + 2*idx] = A; lev1[1 + 2*idx] = B; } } } /* add change to global sum in a threadsafe way */ airThreadMutexLock(task->actx->changeMutex); task->actx->averageChange += change/(sx*sy*sz); task->actx->changeCount += 1; if (task->actx->changeCount == task->actx->numThreads) { /* I must be the last thread to reach this point; all others must have passed the mutex unlock, and are sitting at the barrier */ if (alanStopNot != stop) { /* there was some problem in going from lev0 to lev1, which we deal with now by setting actx->stop */ task->actx->stop = stop; } else if (task->actx->averageChange < task->actx->minAverageChange) { /* we converged */ task->actx->stop = alanStopConverged; } else { /* we keep going */ _alanPerIteration(task->actx, iter); if (task->actx->perIteration) { task->actx->perIteration(task->actx, iter); } } task->actx->averageChange = 0; task->actx->changeCount = 0; } airThreadMutexUnlock(task->actx->changeMutex); /* force all threads to line up here, once per iteration */ airThreadBarrierWait(task->actx->iterBarrier); } if (iter == task->actx->maxIteration) { /* HEY: all threads will agree on this, right? */ task->actx->stop = alanStopMaxIteration; } /* else: the non-alanStopNot value of task->actx->stop made us stop */ return _task; }
static double _nrrdBinaryOpMod(double a, double b) { return AIR_MOD((int)a,(int)b);}
int main(int argc, char *argv[]) { char *me, *err; limnSpline *spline, *warp; hestOpt *hopt=NULL; airArray *mop; int i, M, ret, pause, loop; Nrrd *nout, *ntmp; double *out, minT, maxT, scale, tran[2]; mop = airMopNew(); me = argv[0]; hestOptAdd(&hopt, "i", "spline", airTypeOther, 1, 1, &spline, NULL, "the spline that we want to sample", NULL, NULL, limnHestSpline); hestOptAdd(&hopt, "w", "timewarp", airTypeOther, 1, 1, &warp, "", "how to (optionally) warp the spline domain", NULL, NULL, limnHestSpline); hestOptAdd(&hopt, "loop", NULL, airTypeInt, 0, 0, &loop, NULL, "the last control point is in fact the first"); hestOptAdd(&hopt, "m", "M", airTypeInt, 1, 1, &M, "512", "the number of sample points at which to evalute the spline"); hestOptAdd(&hopt, "t", "tx ty", airTypeDouble, 2, 2, tran, "0.0 0.0", "translation for drawing"); hestOptAdd(&hopt, "s", "scale", airTypeDouble, 1, 1, &scale, "1.0", "scaling for drawing"); hestParseOrDie(hopt, argc-1, argv+1, NULL, me, info, AIR_TRUE, AIR_TRUE, AIR_TRUE); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); spline->loop = loop; if (!( limnSplineInfo2Vector == spline->info )) { fprintf(stderr, "%s: sorry, can only have %s info for PostScript\n", me, airEnumStr(limnSplineInfo, limnSplineInfo2Vector)); airMopError(mop); return 1; } if (warp) { warp->loop = loop; if (!( limnSplineTypeTimeWarp == warp->type )) { fprintf(stderr, "%s: %s spline isn't; its %s\n", me, airEnumStr(limnSplineType, limnSplineTypeTimeWarp), airEnumStr(limnSplineType, warp->type)); airMopError(mop); return 1; } if (loop) { if (!( limnSplineNumPoints(warp) == 1 + limnSplineNumPoints(spline) )) { fprintf(stderr, "%s: # warp points (%d) needs to be 1 more than " "# spline points (%d) for looping\n", me, limnSplineNumPoints(warp), limnSplineNumPoints(spline)); airMopError(mop); return 1; } } else { if (!( limnSplineNumPoints(warp) == limnSplineNumPoints(spline) )) { fprintf(stderr, "%s: # warp points (%d) != # spline points (%d)\n", me, limnSplineNumPoints(warp), limnSplineNumPoints(spline)); airMopError(mop); return 1; } } } airMopAdd(mop, nout=nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, ntmp=nrrdNew(), (airMopper)nrrdNuke, airMopAlways); if (warp) { minT = limnSplineMinT(warp); maxT = limnSplineMaxT(warp); ret = (limnSplineSample(ntmp, warp, minT, M, maxT) || limnSplineNrrdEvaluate(nout, spline, ntmp)); } else { minT = limnSplineMinT(spline); maxT = limnSplineMaxT(spline); ret = limnSplineSample(nout, spline, minT, M, maxT); } if (ret) { airMopAdd(mop, err=biffGetDone(LIMN), airFree, airMopAlways); fprintf(stderr, "%s: trouble:\n%s\n", me, err); airMopError(mop); return 1; } out = (double*)(nout->data); pause = M/150; printf("%%!\n"); printf("1 setlinewidth\n"); printf("%g %g moveto\n", scale*out[0 + 2*0] + tran[0], scale*out[1 + 2*0] + tran[1]); printf("gsave\n"); printf("0.2 setlinewidth\n"); printf("currentpoint newpath 3 0 360 arc stroke\n"); printf("grestore\n"); for (i=1; i<M; i++) { printf("%g %g lineto\n", scale*out[0 + 2*i] + tran[0], scale*out[1 + 2*i] + tran[1]); if (0 == AIR_MOD(i, pause)) { printf("gsave\n"); printf("0.2 setlinewidth\n"); printf("currentpoint newpath 3 0 360 arc stroke\n"); printf("grestore\n"); } } printf("stroke\n"); printf("showpage\n"); airMopOkay(mop); return 0; }