/* ******** limnLightUpdate() ** ** copies information from the _dir vectors to the dir vectors. This ** needs to be called even if there are no viewspace lights, so that ** the dir vectors are set and normalized. If there are no viewspace ** lights, "cam" can actually be passed as NULL, but don't get carried ** away... ** ** returns 1 if there was a problem in the camera, otherwise 0. */ int limnLightUpdate(limnLight *lit, limnCamera *cam) { char me[]="limnLightUpdate", err[BIFF_STRLEN]; double dir[3], _dir[3], uvn[9]={0,0,0,0,0,0,0,0,0}, norm; int i; if (cam) { if (limnCameraUpdate(cam)) { sprintf(err, "%s: trouble in camera", me); biffAdd(LIMN, err); return 1; } ELL_34M_EXTRACT(uvn, cam->V2W); } for (i=0; i<LIMN_LIGHT_NUM; i++) { ELL_3V_COPY(_dir, lit->_dir[i]); if (cam && lit->vsp[i]) { ELL_3MV_MUL(dir, uvn, _dir); } else { ELL_3V_COPY(dir, _dir); } ELL_3V_NORM(dir, dir, norm); ELL_4V_SET_TT(lit->dir[i], float, dir[0], dir[1], dir[2], 0.0); } return 0; }
/* Gives an inital choice of 2 centroids */ void _tenInitcent2(const int gradcount, const double qvals[], const double qpoints[], double centroids[6]) { int i, maxidx; double max, dist; /* Find largest peak in Q-ball */ maxidx = 0; for( i = 0; i < gradcount; i++ ) if( qvals[maxidx] < qvals[i] ) maxidx = i; ELL_3V_COPY( centroids, qpoints +3*maxidx ); /* printf("init: max=%d cent0=[%f %f %f]\n", maxidx, centroids[0], centroids[1], centroids[2]); */ /* Find peak/axis from Q-ball furthest away from first peak */ max = 0; for( i = 0; i < gradcount; i++ ) { dist = _tenPldist(qpoints +3*i, centroids); if (dist > max) { maxidx = i; max = dist; } } ELL_3V_COPY( centroids+3, qpoints +3*maxidx ); /* printf( "\ninit: max=%d cent1=[%f %f %f]\n", maxidx, centroids[3], centroids[4], centroids[5]); */ }
void _tenFiberStep_TensorLine(tenFiberContext *tfx, double step[3]) { double cl, evec0[3], vout[3], vin[3], len; ELL_3V_COPY(evec0, tfx->evec + 3*0); _tenFiberAlign(tfx, evec0); if (tfx->lastDirSet) { ELL_3V_COPY(vin, tfx->lastDir); TEN_T3V_MUL(vout, tfx->dten, tfx->lastDir); ELL_3V_NORM(vout, vout, len); _tenFiberAlign(tfx, vout); /* HEY: is this needed? */ } else { ELL_3V_COPY(vin, evec0); ELL_3V_COPY(vout, evec0); } cl = (tfx->eval[0] - tfx->eval[1])/(tfx->eval[0] + 0.00001); ELL_3V_SCALE_ADD3(step, cl, evec0, (1-cl)*(1-tfx->wPunct), vin, (1-cl)*tfx->wPunct, vout); /* _tenFiberAlign(tfx, step); */ ELL_3V_NORM(step, step, len); if (tfx->anisoSpeedType) { _tenFiberAnisoSpeed(step, *(tfx->anisoSpeed), tfx->anisoSpeedFunc); } }
/* Finds discrete maxima of the tensor (based on emc) and refines them, * storing magnitudes in (malloc'ed) *ls and *vs. Returns the number of * distinct maxima, or -1 on error. ls are sorted in descending order. */ int elfMaximaFind_d(double **ls, double **vs, const double *ten, elfMaximaContext *emc) { unsigned int i; int retval; double *vals; airHeap *heap; if (ls==NULL || vs==NULL || ten==NULL || emc==NULL) return -1; if (emc->vertices_d==NULL) { /* we need to allocate these */ emc->vertices_d = (double*) malloc(sizeof(double)*3*(emc->num/2)); for (i=0; i<emc->num/2; i++) { ELL_3V_COPY(emc->vertices_d+3*i, emc->vertices_f+3*i); } } /* evaluate all unique directions */ vals = (double*) malloc(sizeof(double)*(emc->num/2)); for (i=0; i<emc->num/2; i++) { vals[i]=(*emc->type->sym->s_form_d)(ten, emc->vertices_d+3*i); } heap = airHeapNew(sizeof(double)*3, 20); /* identify discrete maxima */ for (i=0; i<emc->num/2; i++) { unsigned int ni=0; int ismax=1, nb; while (ni<emc->nbstride && (nb=emc->neighbors[emc->nbstride*2*i+ni])!=-1) { if (vals[i]<=vals[nb/2]) { ismax=0; break; } ni++; } if (ismax) { double s=vals[i], v[3]; ELL_3V_COPY(v,emc->vertices_d+3*i); if (emc->refine) /* refine further */ tijk_refine_max_3d_d(&s, v, ten, emc->type, emc->parm); /* add to heap */ airHeapInsert(heap, -s, v); } } /* allocate arrays and return what we have found */ retval=airHeapLength(heap); if (retval>0) { *ls = (double*) malloc(sizeof(double)*retval); *vs = (double*) malloc(sizeof(double)*3*retval); for (i=0; i<(unsigned int)retval; i++) { (*ls)[i]=-airHeapFrontPop(heap, (*vs)+3*i); } } heap=airHeapNix(heap); free(vals); return retval; }
int main(int argc, char *argv[]) { char *me; hestOpt *hopt=NULL; airArray *mop; int *itype, itypeNum, ii; double src[3], last[3], dst[3]; char space[] = " "; me = argv[0]; hestOptAdd(&hopt, NULL, "v1 v2 v3", airTypeDouble, 3, 3, src, NULL, "source triple"); hestOptAdd(&hopt, "t", "type", airTypeEnum, 2, -1, &itype, NULL, "sequence of triple types to convert through", &itypeNum, tenTripleType); hestParseOrDie(hopt, argc-1, argv+1, NULL, me, info, AIR_TRUE, AIR_TRUE, AIR_TRUE); mop = airMopNew(); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); printf("%s", space + strlen(airEnumStr(tenTripleType, itype[0]))); printf("%s", airEnumStr(tenTripleType, itype[0])); ell_3v_print_d(stdout, src); ELL_3V_COPY(last, src); for (ii=1; ii<itypeNum; ii++) { tenTripleConvertSingle_d(dst, itype[ii], src, itype[ii-1]); printf("%s", space + strlen(airEnumStr(tenTripleType, itype[ii]))); printf("%s", airEnumStr(tenTripleType, itype[ii])); ell_3v_print_d(stdout, dst); ELL_3V_COPY(src, dst); } /* tenTripleConvert_d(dst, dstType, src, srcType); tenTripleConvert_d(tst, srcType, dst, dstType); */ /* printf("%s: %s %s --> %s --> %s\n", me, tenTriple->name, airEnumStr(tenTriple, srcType), airEnumStr(tenTriple, dstType), airEnumStr(tenTriple, srcType)); ell_3v_print_d(stdout, src); ell_3v_print_d(stdout, dst); ell_3v_print_d(stdout, tst); */ airMopOkay(mop); return 0; }
int tenDWMRIKeyValueFromExperSpecSet(Nrrd *ndwi, const tenExperSpec *espec) { static char me[]="tenDWMRIKeyValueFromExperSpecSet"; char keystr[AIR_STRLEN_MED], valstr[AIR_STRLEN_MED]; double maxb, bb; unsigned int ii; if (!(ndwi && espec)) { biffAddf(TEN, "%s: got NULL pointer", me); return 1; } nrrdKeyValueAdd(ndwi, tenDWMRIModalityKey, tenDWMRIModalityVal); maxb = tenExperSpecMaxBGet(espec); sprintf(valstr, "%.17g", maxb); nrrdKeyValueAdd(ndwi, tenDWMRIBValueKey, valstr); for (ii=0; ii<espec->imgNum; ii++) { double vec[3]; sprintf(keystr, tenDWMRIGradKeyFmt, ii); ELL_3V_COPY(vec, espec->grad + 3*ii); bb = espec->bval[ii]; /* Thu Dec 20 03:25:20 CST 2012 this rescaling is not, btw, what is causing the small discrepency between ngrad before and after saving to KVPs */ ELL_3V_SCALE(vec, sqrt(bb/maxb), vec); sprintf(valstr, "%.17g %.17g %.17g", vec[0], vec[1], vec[2]); nrrdKeyValueAdd(ndwi, keystr, valstr); } /* HEY what if its a full B-matrix? */ return 0; }
/* ** _hooverLearnLengths() ** ** This is where we enforce the constraint that the volume always fit ** inside a cube with edge length 2, centered at the origin. ** ** volHLen[i] is the HALF the length of the volume along axis i ** ** NOTE: at some point this will be replaced by gageShapeUnitLengths, ** but that will mean API changes for hoover, since right now nothing ** uses or cares about the gageShape struct */ void _hooverLearnLengths(double volHLen[3], double voxLen[3], hooverContext *ctx) { double maxLen; int numSamples[3], numElements[3]; ELL_3V_COPY(numSamples, ctx->volSize); if (nrrdCenterNode == ctx->volCentering) { numElements[0] = numSamples[0]-1; numElements[1] = numSamples[1]-1; numElements[2] = numSamples[2]-1; } else { numElements[0] = numSamples[0]; numElements[1] = numSamples[1]; numElements[2] = numSamples[2]; } volHLen[0] = numElements[0]*ctx->volSpacing[0]; volHLen[1] = numElements[1]*ctx->volSpacing[1]; volHLen[2] = numElements[2]*ctx->volSpacing[2]; maxLen = AIR_MAX(volHLen[0], volHLen[1]); maxLen = AIR_MAX(volHLen[2], maxLen); volHLen[0] /= maxLen; volHLen[1] /= maxLen; volHLen[2] /= maxLen; voxLen[0] = 2*volHLen[0]/numElements[0]; voxLen[1] = 2*volHLen[1]/numElements[1]; voxLen[2] = 2*volHLen[2]/numElements[2]; }
/* Creates an elfMaximaContext, which can then be used to find all * maxima of a symmetric even-order 3D tensor of the given type. * Returns NULL if type is not even-order 3D symmetric. * * The initial maximum sampling is at the vertices of a subdivided * icosahedron - level=3 (321 unique directions) should be * sufficient. Larger levels reduce the risk of missing one of two (or * more) very close maxima, at increased computational cost. */ elfMaximaContext *elfMaximaContextNew(const tijk_type *type, unsigned int level) { elfMaximaContext *retval; limnPolyData *sphere; unsigned int vert; if (type==NULL || type->dim!=3 || type->sym==NULL || type->order%2!=0) return NULL; /* elfMaxima cannot be used with this tensor type */ sphere = limnPolyDataNew(); limnPolyDataIcoSphere(sphere, 0, level); retval = (elfMaximaContext*) malloc(sizeof(elfMaximaContext)); retval->num = sphere->xyzwNum; retval->type = type; retval->parm = NULL; retval->refine = 1; /* extract neighborhood info (needed to take discrete maxima) */ limnPolyDataNeighborArray(&(retval->neighbors), &(retval->nbstride), sphere); /* copy over vertices in single and double precision */ retval->vertices_f = (float*) malloc(sizeof(float)*3*(sphere->xyzwNum/2)); for (vert=0; vert<sphere->xyzwNum; vert+=2) { ELL_3V_COPY(retval->vertices_f+3*(vert/2), sphere->xyzw+4*vert); } retval->vertices_d = NULL; sphere=limnPolyDataNix(sphere); return retval; }
/* ** all pvls' needD --> ctx's needD */ void _gageNeedDUpdate(gageContext *ctx) { char me[]="_gageNeedDUpdate"; gagePerVolume *pvl; int needD[3]; unsigned int pvlIdx; if (ctx->verbose) fprintf(stderr, "%s: hello\n", me); ELL_3V_SET(needD, 0, 0, 0); for (pvlIdx=0; pvlIdx<ctx->pvlNum; pvlIdx++) { pvl = ctx->pvl[pvlIdx]; needD[0] |= pvl->needD[0]; needD[1] |= pvl->needD[1]; needD[2] |= pvl->needD[2]; } if (!ELL_3V_EQUAL(needD, ctx->needD)) { if (ctx->verbose) { fprintf(stderr, "%s: updating ctx's needD to (%d,%d,%d)\n", me, needD[0], needD[1], needD[2]); } ELL_3V_COPY(ctx->needD, needD); ctx->flag[gageCtxFlagNeedD] = AIR_TRUE; } if (ctx->verbose) fprintf(stderr, "%s: bye\n", me); return; }
/* ** for each pvl: pvl's query --> pvl's needD */ void _gagePvlNeedDUpdate(gageContext *ctx) { char me[]="_gagePvlNeedDUpdate"; gagePerVolume *pvl; int que, needD[3]; unsigned int pvlIdx; if (ctx->verbose) fprintf(stderr, "%s: hello\n", me); for (pvlIdx=0; pvlIdx<ctx->pvlNum; pvlIdx++) { pvl = ctx->pvl[pvlIdx]; if (pvl->flag[gagePvlFlagQuery]) { ELL_3V_SET(needD, 0, 0, 0); que = pvl->kind->itemMax+1; do { que--; if (GAGE_QUERY_ITEM_TEST(pvl->query, que)) { needD[pvl->kind->table[que].needDeriv] = 1; } } while (que); if (!ELL_3V_EQUAL(needD, pvl->needD)) { if (ctx->verbose) { fprintf(stderr, "%s: updating pvl[%d]'s needD to (%d,%d,%d)\n", me, pvlIdx, needD[0], needD[1], needD[2]); } ELL_3V_COPY(pvl->needD, needD); pvl->flag[gagePvlFlagNeedD] = AIR_TRUE; } } } if (ctx->verbose) fprintf(stderr, "%s: bye\n", me); return; }
int _echoRayIntx_Instance(RAYINTX_ARGS(Instance)) { echoPos_t a[4], b[4], tmp; echoRay iray; /* ELL_3V_COPY(iray.from, ray->from); ELL_3V_COPY(iray.dir, ray->dir); */ ELL_4V_SET(a, ray->from[0], ray->from[1], ray->from[2], 1); ELL_4MV_MUL(b, obj->Mi, a); ELL_34V_HOMOG(iray.from, b); ELL_4V_SET(a, ray->dir[0], ray->dir[1], ray->dir[2], 0); ELL_4MV_MUL(b, obj->Mi, a); ELL_3V_COPY(iray.dir, b); if (tstate->verbose) { fprintf(stderr, "%s%s: dir (%g,%g,%g)\n%s -- Mi --> " "(%g,%g,%g,%g)\n%s --> (%g,%g,%g)\n", _echoDot(tstate->depth), "_echoRayIntx_Instance", a[0], a[1], a[2], _echoDot(tstate->depth), b[0], b[1], b[2], b[3], _echoDot(tstate->depth), iray.dir[0], iray.dir[1], iray.dir[2]); } iray.neer = ray->neer; iray.faar = ray->faar; iray.shadow = ray->shadow; if (_echoRayIntx[obj->obj->type](intx, &iray, obj->obj, parm, tstate)) { ELL_4V_SET(a, intx->norm[0], intx->norm[1], intx->norm[2], 0); ELL_4MV_TMUL(b, obj->Mi, a); ELL_3V_COPY(intx->norm, b); ELL_3V_NORM(intx->norm, intx->norm, tmp); if (tstate->verbose) { fprintf(stderr, "%s%s: hit a %d (at t=%g) with M == \n", _echoDot(tstate->depth), "_echoRayIntx_Instance", obj->obj->type, intx->t); ell_4m_PRINT(stderr, obj->M); fprintf(stderr, "%s ... (det = %f), and Mi == \n", _echoDot(tstate->depth), ell_4m_DET(obj->M)); ell_4m_PRINT(stderr, obj->Mi); } return AIR_TRUE; } /* else */ return AIR_FALSE; }
static void _xyz_ev(double xyz[3], const double _ev[3]) { double ev[3], tmp; ELL_3V_COPY(ev, _ev); ELL_SORT3(ev[0], ev[1], ev[2], tmp); ELL_3MV_MUL(xyz, _xyzmat, ev); }
void tenTripleConvertSingle_f(float _dst[3], int dstType, const float _src[3], const int srcType) { double dst[3], src[3]; ELL_3V_COPY(src, _src); tenTripleConvertSingle_d(dst, dstType, src, srcType); ELL_3V_COPY_TT(_dst, float, dst); }
void gageShapeItoW(gageShape *shape, double _world[3], double _index[3]) { double world[4], index[4]; ELL_3V_COPY(index, _index); index[3] = 1.0; ELL_4MV_MUL(world, shape->ItoW, index); ELL_3V_SCALE(_world, 1.0/world[3], world); }
void gageShapeWtoI(gageShape *shape, double _index[3], double _world[3]) { double index[4], world[4]; ELL_3V_COPY(world, _world); world[3] = 1.0; ELL_4MV_MUL(index, shape->WtoI, world); ELL_3V_SCALE(_index, 1.0/index[3], index); }
/* ** ------------------------------------------------------------------- ** ------------------------------------------------------------------- ** The _tenFiberStep_* routines are responsible for putting a step into ** the given step[] vector. Without anisoStepSize, this should be ** UNIT LENGTH, with anisoStepSize, its scaled by that anisotropy measure */ void _tenFiberStep_Evec1(tenFiberContext *tfx, double step[3]) { ELL_3V_COPY(step, tfx->evec + 3*0); _tenFiberAlign(tfx, step); if (tfx->anisoSpeedType) { _tenFiberAnisoSpeed(step, *(tfx->anisoSpeed), tfx->anisoSpeedFunc); } }
void gageShapeBoundingBox(double min[3], double max[3], const gageShape *shape) { /* static const char me[]="gageShapeBoundingBox"; */ double minIdx[3], maxIdx[3], cornerIdx[8][3], tmp[3]; unsigned int ii; if (!( min && max && shape )) { return; } if (nrrdCenterNode == shape->center) { ELL_3V_SET(minIdx, 0, 0, 0); ELL_3V_SET(maxIdx, shape->size[0]-1, shape->size[1]-1, shape->size[2]-1); } else { ELL_3V_SET(minIdx, -0.5, -0.5, -0.5); ELL_3V_SET(maxIdx, shape->size[0]-0.5, shape->size[1]-0.5, shape->size[2]-0.5); } ELL_3V_SET(cornerIdx[0], minIdx[0], minIdx[1], minIdx[2]); ELL_3V_SET(cornerIdx[1], maxIdx[0], minIdx[1], minIdx[2]); ELL_3V_SET(cornerIdx[2], minIdx[0], maxIdx[1], minIdx[2]); ELL_3V_SET(cornerIdx[3], maxIdx[0], maxIdx[1], minIdx[2]); ELL_3V_SET(cornerIdx[4], minIdx[0], minIdx[1], maxIdx[2]); ELL_3V_SET(cornerIdx[5], maxIdx[0], minIdx[1], maxIdx[2]); ELL_3V_SET(cornerIdx[6], minIdx[0], maxIdx[1], maxIdx[2]); ELL_3V_SET(cornerIdx[7], maxIdx[0], maxIdx[1], maxIdx[2]); gageShapeItoW(shape, tmp, cornerIdx[0]); ELL_3V_COPY(min, tmp); ELL_3V_COPY(max, tmp); for (ii=1; ii<8; ii++) { gageShapeItoW(shape, tmp, cornerIdx[ii]); ELL_3V_MIN(min, min, tmp); ELL_3V_MAX(max, max, tmp); } return; }
void echoEnvmapLookup(echoCol_t rgb[3], echoPos_t norm[3], Nrrd *envmap) { int qn; float *data; #if ECHO_POS_FLOAT qn = limnVtoQN_f[limnQN16octa](norm); #else qn = limnVtoQN_d[limnQN16octa](norm); #endif data = (float*)(envmap->data) + 3*qn; ELL_3V_COPY(rgb, data); }
void _echoPosSet(echoPos_t *p3, echoPos_t *matx, echoPos_t *p4) { echoPos_t a[4], b[4]; if (matx) { ELL_4V_SET(a, p4[0], p4[1], p4[2], 1); ELL_4MV_MUL(b, matx, a); ELL_34V_HOMOG(p3, b); } else { ELL_3V_COPY(p3, p4); } }
void gageShapeWtoI(gageShape *shape, double _index[3], double _world[3]) { /* char me[]="gageShapeWtoI"; */ double index[4], world[4]; /* fprintf(stderr, "!%s: hello %p %p %p; %p\n", me, shape, _index, _world, shape->WtoI); */ ELL_3V_COPY(world, _world); world[3] = 1.0; ELL_4MV_MUL(index, shape->WtoI, world); ELL_3V_SCALE(_index, 1.0/index[3], index); }
/* ******* echoLightColor() ** ** sets "col" to RGB color for current sample of given light, which ** is at distance Ldist. Knowing distance allows computation of the ** inverse square fall-off of light intensity */ void echoLightColor(echoCol_t rgb[3], echoPos_t Ldist, echoObject *light, echoRTParm *parm, echoThreadState *tstate) { echoCol_t rgba[4], falloff; echoPos_t x, y; x = tstate->jitt[0 + 2*echoJittableLight] + 0.5; y = tstate->jitt[1 + 2*echoJittableLight] + 0.5; if (light->ntext) { echoTextureLookup(rgba, light->ntext, x, y, parm); ELL_3V_COPY(rgb, rgba); } else { ELL_3V_COPY(rgb, light->rgba); } ELL_3V_SCALE(rgb, light->mat[echoMatterLightPower], rgb); if (light->mat[echoMatterLightUnit]) { falloff = AIR_CAST(echoCol_t, light->mat[echoMatterLightUnit]/Ldist); falloff *= falloff; ELL_3V_SCALE(rgb, falloff, rgb); } return; }
int _echoRayIntx_TriMesh(RAYINTX_ARGS(TriMesh)) { echoPos_t *pos, vert0[3], edge0[3], edge1[3], pvec[3], qvec[3], tvec[3], det, t, tmax, u, v, tmp; echoTriMesh *trim; int i, ret; AIR_UNUSED(parm); trim = TRIMESH(obj); if (!_echoRayIntx_CubeSolid(&t, &tmax, trim->min[0], trim->max[0], trim->min[1], trim->max[1], trim->min[2], trim->max[2], ray)) { if (tstate->verbose) { fprintf(stderr, "%s%s: trimesh bbox (%g,%g,%g) --> (%g,%g,%g) not hit\n", _echoDot(tstate->depth), "_echoRayIntx_TriMesh", trim->min[0], trim->min[1], trim->min[2], trim->max[0], trim->max[1], trim->max[2]); } return AIR_FALSE; } /* stupid linear search for now */ ret = AIR_FALSE; for (i=0; i<trim->numF; i++) { pos = trim->pos + 3*trim->vert[0 + 3*i]; ELL_3V_COPY(vert0, pos); pos = trim->pos + 3*trim->vert[1 + 3*i]; ELL_3V_SUB(edge0, pos, vert0); pos = trim->pos + 3*trim->vert[2 + 3*i]; ELL_3V_SUB(edge1, pos, vert0); TRI_INTX(ray, vert0, edge0, edge1, pvec, qvec, tvec, det, t, u, v, (v < 0.0 || u + v > 1.0), continue); if (ray->shadow) { return AIR_TRUE; } intx->t = ray->faar = t; ELL_3V_CROSS(intx->norm, edge0, edge1); ELL_3V_NORM(intx->norm, intx->norm, tmp); intx->obj = (echoObject *)obj; intx->face = i; ret = AIR_TRUE; } /* does NOT set u, v */ return ret; }
int tenExperSpecGradSingleBValSet(tenExperSpec *espec, int insertB0, double bval, const double *grad, unsigned int gradNum) { static const char me[]="tenExperSpecGradSingleBValSet"; unsigned int ii, imgNum, ei; if (!espec) { biffAddf(TEN, "%s: got NULL pointer", me); return 1; } if (insertB0 && !ELL_3V_LEN(grad + 3*0)) { biffAddf(TEN, "%s: wanted insertB0 but gradients " "already start with (0,0,0)", me); return 1; } imgNum = gradNum + !!insertB0; if (_experAlloc(espec, imgNum)) { biffAddf(TEN, "%s: couldn't allocate", me); return 1; } if (insertB0) { espec->bval[0] = 0; ELL_3V_SET(espec->grad + 3*0, 1, 0, 0); ei = 1; } else { ei = 0; } for (ii=0; ii<gradNum; ei++, ii++) { espec->bval[ei] = bval; ELL_3V_COPY(espec->grad + 3*ei, grad + 3*ii); /* espec->wght[ii] = 1.0; */ } return 0; }
/* ** bins on boundary now extend to infinity; so the only time this ** returns NULL (indicating error) is for non-existent positions */ pushBin * _pushBinLocate(pushContext *pctx, double *_posWorld) { static const char me[]="_pushBinLocate"; double posWorld[4], posIdx[4]; unsigned int axi, eidx[3], binIdx; if (!ELL_3V_EXISTS(_posWorld)) { biffAddf(PUSH, "%s: non-existent position (%g,%g,%g)", me, _posWorld[0], _posWorld[1], _posWorld[2]); return NULL; } if (pctx->binSingle) { binIdx = 0; } else { ELL_3V_COPY(posWorld, _posWorld); posWorld[3] = 1.0; ELL_4MV_MUL(posIdx, pctx->gctx->shape->WtoI, posWorld); ELL_34V_HOMOG(posIdx, posIdx); for (axi=0; axi<3; axi++) { eidx[axi] = airIndexClamp(-0.5, posIdx[axi], pctx->gctx->shape->size[axi]-0.5, pctx->binsEdge[axi]); } binIdx = (eidx[0] + pctx->binsEdge[0]*(eidx[1] + pctx->binsEdge[1]*eidx[2])); } /* fprintf(stderr, "!%s: bin(%g,%g,%g) = %u\n", me, _posWorld[0], _posWorld[1], _posWorld[2], binIdx); */ return pctx->bin + binIdx; }
void tend_helixDoit(Nrrd *nout, double bnd, double orig[3], double i2w[9], double mf[9], double r, double R, double S, double angle, int incrtwist, double ev[3], double bgEval) { int sx, sy, sz, xi, yi, zi; double th, t0, t1, t2, t3, v1, v2, wpos[3], vpos[3], mfT[9], W2H[9], H2W[9], H2C[9], C2H[9], fv[3], rv[3], uv[3], mA[9], mB[9], inside, tmp[3], len; float *out; sx = nout->axis[1].size; sy = nout->axis[2].size; sz = nout->axis[3].size; out = (float*)nout->data; ELL_3M_TRANSPOSE(mfT, mf); for (zi=0; zi<sz; zi++) { fprintf(stderr, "zi = %d/%d\n", zi, sz); for (yi=0; yi<sy; yi++) { for (xi=0; xi<sx; xi++) { ELL_3V_SET(tmp, xi, yi, zi); ELL_3MV_MUL(vpos, i2w, tmp); ELL_3V_INCR(vpos, orig); #define WPOS(pos, th) ELL_3V_SET((pos),R*cos(th), R*sin(th), S*(th)/(2*AIR_PI)) #define VAL(th) (WPOS(wpos, th), ELL_3V_DIST(wpos, vpos)) #define RR 0.61803399 #define CC (1.0-RR) #define SHIFT3(a,b,c,d) (a)=(b); (b)=(c); (c)=(d) #define SHIFT2(a,b,c) (a)=(b); (b)=(c) th = atan2(vpos[1], vpos[0]); th += 2*AIR_PI*floor(0.5 + vpos[2]/S - th/(2*AIR_PI)); if (S*th/(2*AIR_PI) > vpos[2]) { t0 = th - AIR_PI; t3 = th; } else { t0 = th; t3 = th + AIR_PI; } t1 = RR*t0 + CC*t3; t2 = CC*t0 + RR*t3; v1 = VAL(t1); v2 = VAL(t2); while ( t3-t0 > 0.000001*(AIR_ABS(t1)+AIR_ABS(t2)) ) { if (v1 < v2) { SHIFT3(t3, t2, t1, CC*t0 + RR*t2); SHIFT2(v2, v1, VAL(t1)); } else { SHIFT3(t0, t1, t2, RR*t1 + CC*t3); SHIFT2(v1, v2, VAL(t2)); } } /* t1 (and t2) are now the th for which the point on the helix (R*cos(th), R*sin(th), S*(th)/(2*AIR_PI)) is closest to vpos */ WPOS(wpos, t1); ELL_3V_SUB(wpos, vpos, wpos); ELL_3V_SET(fv, -R*sin(t1), R*cos(t1), S/AIR_PI); /* helix tangent */ ELL_3V_NORM(fv, fv, len); ELL_3V_COPY(rv, wpos); ELL_3V_NORM(rv, rv, len); len = ELL_3V_DOT(rv, fv); ELL_3V_SCALE(tmp, -len, fv); ELL_3V_ADD2(rv, rv, tmp); ELL_3V_NORM(rv, rv, len); /* rv now normal to helix, closest to pointing to vpos */ ELL_3V_CROSS(uv, rv, fv); ELL_3V_NORM(uv, uv, len); /* (rv,fv,uv) now right-handed frame */ ELL_3MV_ROW0_SET(W2H, uv); /* as is (uv,rv,fv) */ ELL_3MV_ROW1_SET(W2H, rv); ELL_3MV_ROW2_SET(W2H, fv); ELL_3M_TRANSPOSE(H2W, W2H); inside = 0.5 - 0.5*airErf((ELL_3V_LEN(wpos)-r)/(bnd + 0.0001)); if (incrtwist) { th = angle*ELL_3V_LEN(wpos)/r; } else { th = angle; } ELL_3M_ROTATE_Y_SET(H2C, th); ELL_3M_TRANSPOSE(C2H, H2C); ELL_3M_SCALE_SET(mA, AIR_LERP(inside, bgEval, ev[1]), AIR_LERP(inside, bgEval, ev[2]), AIR_LERP(inside, bgEval, ev[0])); ELL_3M_MUL(mB, mA, H2C); ELL_3M_MUL(mA, mB, W2H); ELL_3M_MUL(mB, mA, mf); ELL_3M_MUL(mA, C2H, mB); ELL_3M_MUL(mB, H2W, mA); ELL_3M_MUL(mA, mfT, mB); TEN_M2T_TT(out, float, mA); out[0] = 1.0; out += 7; } } } return; }
int tend_helixMain(int argc, char **argv, char *me, hestParm *hparm) { int pret; hestOpt *hopt = NULL; char *perr, *err; airArray *mop; int size[3], nit; Nrrd *nout; double R, r, S, bnd, angle, ev[3], ip[3], iq[4], mp[3], mq[4], tmp[9], orig[3], i2w[9], rot[9], mf[9], spd[4][3], bge; char *outS; hestOptAdd(&hopt, "s", "size", airTypeInt, 3, 3, size, NULL, "sizes along fast, medium, and slow axes of the sampled volume, " "often called \"X\", \"Y\", and \"Z\". It is best to use " "slightly different sizes here, to expose errors in interpreting " "axis ordering (e.g. \"-s 39 40 41\")"); hestOptAdd(&hopt, "ip", "image orientation", airTypeDouble, 3, 3, ip, "0 0 0", "quaternion quotient space orientation of image"); hestOptAdd(&hopt, "mp", "measurement orientation", airTypeDouble, 3, 3, mp, "0 0 0", "quaternion quotient space orientation of measurement frame"); hestOptAdd(&hopt, "b", "boundary", airTypeDouble, 1, 1, &bnd, "10", "parameter governing how fuzzy the boundary between high and " "low anisotropy is. Use \"-b 0\" for no fuzziness"); hestOptAdd(&hopt, "r", "little radius", airTypeDouble, 1, 1, &r, "30", "(minor) radius of cylinder tracing helix"); hestOptAdd(&hopt, "R", "big radius", airTypeDouble, 1, 1, &R, "50", "(major) radius of helical turns"); hestOptAdd(&hopt, "S", "spacing", airTypeDouble, 1, 1, &S, "100", "spacing between turns of helix (along its axis)"); hestOptAdd(&hopt, "a", "angle", airTypeDouble, 1, 1, &angle, "60", "maximal angle of twist of tensors along path. There is no " "twist at helical core of path, and twist increases linearly " "with radius around this path. Positive twist angle with " "positive spacing resulting in a right-handed twist around a " "right-handed helix. "); hestOptAdd(&hopt, "nit", NULL, airTypeInt, 0, 0, &nit, NULL, "changes behavior of twist angle as function of distance from " "center of helical core: instead of increasing linearly as " "describe above, be at a constant angle"); hestOptAdd(&hopt, "ev", "eigenvalues", airTypeDouble, 3, 3, ev, "0.006 0.002 0.001", "eigenvalues of tensors (in order) along direction of coil, " "circumferential around coil, and radial around coil. "); hestOptAdd(&hopt, "bg", "background", airTypeDouble, 1, 1, &bge, "0.5", "eigenvalue of isotropic background"); hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-", "output file"); mop = airMopNew(); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); USAGE(_tend_helixInfoL); JUSTPARSE(); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); nout = nrrdNew(); airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways); if (nrrdMaybeAlloc_va(nout, nrrdTypeFloat, 4, AIR_CAST(size_t, 7), AIR_CAST(size_t, size[0]), AIR_CAST(size_t, size[1]), AIR_CAST(size_t, size[2]))) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble allocating output:\n%s\n", me, err); airMopError(mop); return 1; } ELL_4V_SET(iq, 1.0, ip[0], ip[1], ip[2]); ell_q_to_3m_d(rot, iq); ELL_3V_SET(orig, -2*R + 2*R/size[0], -2*R + 2*R/size[1], -2*R + 2*R/size[2]); ELL_3M_ZERO_SET(i2w); ELL_3M_DIAG_SET(i2w, 4*R/size[0], 4*R/size[1], 4*R/size[2]); ELL_3MV_MUL(tmp, rot, orig); ELL_3V_COPY(orig, tmp); ELL_3M_MUL(tmp, rot, i2w); ELL_3M_COPY(i2w, tmp); ELL_4V_SET(mq, 1.0, mp[0], mp[1], mp[2]); ell_q_to_3m_d(mf, mq); tend_helixDoit(nout, bnd, orig, i2w, mf, r, R, S, angle*AIR_PI/180, !nit, ev, bge); nrrdSpaceSet(nout, nrrdSpaceRightAnteriorSuperior); nrrdSpaceOriginSet(nout, orig); ELL_3V_SET(spd[0], AIR_NAN, AIR_NAN, AIR_NAN); ELL_3MV_COL0_GET(spd[1], i2w); ELL_3MV_COL1_GET(spd[2], i2w); ELL_3MV_COL2_GET(spd[3], i2w); nrrdAxisInfoSet_va(nout, nrrdAxisInfoSpaceDirection, spd[0], spd[1], spd[2], spd[3]); nrrdAxisInfoSet_va(nout, nrrdAxisInfoCenter, nrrdCenterUnknown, nrrdCenterCell, nrrdCenterCell, nrrdCenterCell); nrrdAxisInfoSet_va(nout, nrrdAxisInfoKind, nrrdKind3DMaskedSymMatrix, nrrdKindSpace, nrrdKindSpace, nrrdKindSpace); nout->measurementFrame[0][0] = mf[0]; nout->measurementFrame[1][0] = mf[1]; nout->measurementFrame[2][0] = mf[2]; nout->measurementFrame[0][1] = mf[3]; nout->measurementFrame[1][1] = mf[4]; nout->measurementFrame[2][1] = mf[5]; nout->measurementFrame[0][2] = mf[6]; nout->measurementFrame[1][2] = mf[7]; nout->measurementFrame[2][2] = mf[8]; if (nrrdSave(outS, nout, NULL)) { airMopAdd(mop, err=biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: trouble writing:\n%s\n", me, err); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
int main(int argc, const char *argv[]) { const char *me; char *err, *outS; float p[3], q[4], mR[9], eval[3]={0,0,0}, scale[3], len, sh, cl, cp, qA, qB; float matA[16], matB[16], os, rad, AB[2]; hestOpt *hopt=NULL; airArray *mop; limnObject *obj; limnLook *look; int lookRod, lookSoid; int partIdx=-1; /* sssh */ int res, axis, sphere; FILE *file; me = argv[0]; hestOptAdd(&hopt, "sc", "scalings", airTypeFloat, 3, 3, scale, "1 1 1", "axis-aligned scaling to do on ellipsoid"); hestOptAdd(&hopt, "AB", "A, B exponents", airTypeFloat, 2, 2, AB, "nan nan", "Directly set the A, B parameters to the superquadric surface, " "over-riding the default behavior of determining them from the " "scalings \"-sc\" as superquadric tensor glyphs"); hestOptAdd(&hopt, "os", "over-all scaling", airTypeFloat, 1, 1, &os, "1", "over-all scaling (multiplied by scalings)"); hestOptAdd(&hopt, "sh", "superquad sharpness", airTypeFloat, 1, 1, &sh, "0", "how much to sharpen edges as a " "function of differences between eigenvalues"); hestOptAdd(&hopt, "sphere", NULL, airTypeInt, 0, 0, &sphere, NULL, "use a sphere instead of a superquadric"); hestOptAdd(&hopt, "p", "x y z", airTypeFloat, 3, 3, p, "0 0 0", "location in quaternion quotient space"); hestOptAdd(&hopt, "r", "radius", airTypeFloat, 1, 1, &rad, "0.015", "black axis cylinder radius (or 0.0 to not drawn these)"); hestOptAdd(&hopt, "res", "resolution", airTypeInt, 1, 1, &res, "25", "tesselation resolution for both glyph and axis cylinders"); hestOptAdd(&hopt, "o", "output OFF", airTypeString, 1, 1, &outS, "out.off", "output file to save OFF into"); hestParseOrDie(hopt, argc-1, argv+1, NULL, me, info, AIR_TRUE, AIR_TRUE, AIR_TRUE); mop = airMopNew(); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); obj = limnObjectNew(100, AIR_FALSE); airMopAdd(mop, obj, (airMopper)limnObjectNix, airMopAlways); /* create limnLooks for ellipsoid and for rods */ lookSoid = limnObjectLookAdd(obj); look = obj->look + lookSoid; ELL_4V_SET(look->rgba, 1, 1, 1, 1); ELL_3V_SET(look->kads, 0.2, 0.8, 0); look->spow = 0; lookRod = limnObjectLookAdd(obj); look = obj->look + lookRod; ELL_4V_SET(look->rgba, 0, 0, 0, 1); ELL_3V_SET(look->kads, 1, 0, 0); look->spow = 0; ELL_4V_SET(q, 1, p[0], p[1], p[2]); ELL_4V_NORM(q, q, len); ell_q_to_3m_f(mR, q); if (AIR_EXISTS(AB[0]) && AIR_EXISTS(AB[1])) { qA = AB[0]; qB = AB[1]; axis = 2; } else { ELL_3V_SCALE(scale, os, scale); ELL_3V_COPY(eval, scale); ELL_SORT3(eval[0], eval[1], eval[2], cl); cl = (eval[0] - eval[1])/(eval[0] + eval[1] + eval[2]); cp = 2*(eval[1] - eval[2])/(eval[0] + eval[1] + eval[2]); if (cl > cp) { axis = ELL_MAX3_IDX(scale[0], scale[1], scale[2]); qA = pow(1-cp, sh); qB = pow(1-cl, sh); } else { axis = ELL_MIN3_IDX(scale[0], scale[1], scale[2]); qA = pow(1-cl, sh); qB = pow(1-cp, sh); } /* fprintf(stderr, "eval = %g %g %g -> cl=%g %s cp=%g -> axis = %d\n", eval[0], eval[1], eval[2], cl, cl > cp ? ">" : "<", cp, axis); */ } if (sphere) { partIdx = limnObjectPolarSphereAdd(obj, lookSoid, 0, 2*res, res); } else { partIdx = limnObjectPolarSuperquadAdd(obj, lookSoid, axis, qA, qB, 2*res, res); } ELL_4M_IDENTITY_SET(matA); ELL_4M_SCALE_SET(matB, scale[0], scale[1], scale[2]); ell_4m_post_mul_f(matA, matB); ELL_43M_INSET(matB, mR); ell_4m_post_mul_f(matA, matB); limnObjectPartTransform(obj, partIdx, matA); if (rad) { partIdx = limnObjectCylinderAdd(obj, lookRod, 0, res); ELL_4M_IDENTITY_SET(matA); ELL_4M_SCALE_SET(matB, (1-eval[0])/2, rad, rad); ell_4m_post_mul_f(matA, matB); ELL_4M_TRANSLATE_SET(matB, (1+eval[0])/2, 0.0, 0.0); ell_4m_post_mul_f(matA, matB); limnObjectPartTransform(obj, partIdx, matA); partIdx = limnObjectCylinderAdd(obj, lookRod, 0, res); ELL_4M_IDENTITY_SET(matA); ELL_4M_SCALE_SET(matB, (1-eval[0])/2, rad, rad); ell_4m_post_mul_f(matA, matB); ELL_4M_TRANSLATE_SET(matB, -(1+eval[0])/2, 0.0, 0.0); ell_4m_post_mul_f(matA, matB); limnObjectPartTransform(obj, partIdx, matA); partIdx = limnObjectCylinderAdd(obj, lookRod, 1, res); ELL_4M_IDENTITY_SET(matA); ELL_4M_SCALE_SET(matB, rad, (1-eval[1])/2, rad); ell_4m_post_mul_f(matA, matB); ELL_4M_TRANSLATE_SET(matB, 0.0, (1+eval[1])/2, 0.0); ell_4m_post_mul_f(matA, matB); limnObjectPartTransform(obj, partIdx, matA); partIdx = limnObjectCylinderAdd(obj, lookRod, 1, res); ELL_4M_IDENTITY_SET(matA); ELL_4M_SCALE_SET(matB, rad, (1-eval[1])/2, rad); ell_4m_post_mul_f(matA, matB); ELL_4M_TRANSLATE_SET(matB, 0.0, -(1+eval[1])/2, 0.0); ell_4m_post_mul_f(matA, matB); limnObjectPartTransform(obj, partIdx, matA); partIdx = limnObjectCylinderAdd(obj, lookRod, 2, res); ELL_4M_IDENTITY_SET(matA); ELL_4M_SCALE_SET(matB, rad, rad, (1-eval[2])/2); ell_4m_post_mul_f(matA, matB); ELL_4M_TRANSLATE_SET(matB, 0.0, 0.0, (1+eval[2])/2); ell_4m_post_mul_f(matA, matB); limnObjectPartTransform(obj, partIdx, matA); partIdx = limnObjectCylinderAdd(obj, lookRod, 2, res); ELL_4M_IDENTITY_SET(matA); ELL_4M_SCALE_SET(matB, rad, rad, (1-eval[2])/2); ell_4m_post_mul_f(matA, matB); ELL_4M_TRANSLATE_SET(matB, 0.0, 0.0, -(1+eval[2])/2); ell_4m_post_mul_f(matA, matB); limnObjectPartTransform(obj, partIdx, matA); } file = airFopen(outS, stdout, "w"); airMopAdd(mop, file, (airMopper)airFclose, airMopAlways); if (limnObjectWriteOFF(file, obj)) { airMopAdd(mop, err = biffGetDone(LIMN), airFree, airMopAlways); fprintf(stderr, "%s: trouble:\n%s\n", me, err); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
/* ******** echoListSplit() ** ** returns a echoObjectSplit to point to the same things as pointed ** to by the given echoObjectList */ echoObject * echoListSplit(echoScene *scene, echoObject *list, int axis) { echoPos_t lo[3], hi[3], loest0[3], hiest0[3], loest1[3], hiest1[3]; double *mids; echoObject *o, *split, *list0, *list1; int i, splitIdx, len; if (!( echoTypeList == list->type || echoTypeAABBox == list->type )) { return list; } len = LIST(list)->objArr->len; if (len <= ECHO_LEN_SMALL_ENOUGH) { /* there is nothing or only one object */ return list; } split = echoObjectNew(scene, echoTypeSplit); list0 = echoObjectNew(scene, echoTypeList); list1 = echoObjectNew(scene, echoTypeList); SPLIT(split)->axis = axis; SPLIT(split)->obj0 = list0; SPLIT(split)->obj1 = list1; mids = (double *)malloc(2 * len * sizeof(double)); for (i=0; i<len; i++) { o = LIST(list)->obj[i]; echoBoundsGet(lo, hi, o); mids[0 + 2*i] = (lo[axis] + hi[axis])/2; *((unsigned int *)(mids + 1 + 2*i)) = i; } /* overkill, I know, I know */ qsort(mids, len, 2*sizeof(double), (int (*)(const void *, const void *))_echoPosCompare); /* for (i=0; i<len; i++) { printf("%d -> %g\n", i, mids[0 + 2*i]); } */ splitIdx = len/2; /* printf("splitIdx = %d\n", splitIdx); */ ELL_3V_SET(loest0, ECHO_POS_MAX, ECHO_POS_MAX, ECHO_POS_MAX); ELL_3V_SET(loest1, ECHO_POS_MAX, ECHO_POS_MAX, ECHO_POS_MAX); ELL_3V_SET(hiest0, ECHO_POS_MIN, ECHO_POS_MIN, ECHO_POS_MIN); ELL_3V_SET(hiest1, ECHO_POS_MIN, ECHO_POS_MIN, ECHO_POS_MIN); airArrayLenSet(LIST(list0)->objArr, splitIdx); for (i=0; i<splitIdx; i++) { o = LIST(list)->obj[*((unsigned int *)(mids + 1 + 2*i))]; LIST(list0)->obj[i] = o; echoBoundsGet(lo, hi, o); /* printf("000 lo = (%g,%g,%g), hi = (%g,%g,%g)\n", lo[0], lo[1], lo[2], hi[0], hi[1], hi[2]); */ ELL_3V_MIN(loest0, loest0, lo); ELL_3V_MAX(hiest0, hiest0, hi); } airArrayLenSet(LIST(list1)->objArr, len-splitIdx); for (i=splitIdx; i<len; i++) { o = LIST(list)->obj[*((unsigned int *)(mids + 1 + 2*i))]; LIST(list1)->obj[i-splitIdx] = o; echoBoundsGet(lo, hi, o); /* printf("111 lo = (%g,%g,%g), hi = (%g,%g,%g)\n", lo[0], lo[1], lo[2], hi[0], hi[1], hi[2]); */ ELL_3V_MIN(loest1, loest1, lo); ELL_3V_MAX(hiest1, hiest1, hi); } /* printf("0: loest = (%g,%g,%g); hiest = (%g,%g,%g)\n", loest0[0], loest0[1], loest0[2], hiest0[0], hiest0[1], hiest0[2]); printf("1: loest = (%g,%g,%g); hiest = (%g,%g,%g)\n", loest1[0], loest1[1], loest1[2], hiest1[0], hiest1[1], hiest1[2]); */ ELL_3V_COPY(SPLIT(split)->min0, loest0); ELL_3V_COPY(SPLIT(split)->max0, hiest0); ELL_3V_COPY(SPLIT(split)->min1, loest1); ELL_3V_COPY(SPLIT(split)->max1, hiest1); /* we can't delete the list object here, we just gut it so that there's nothing substantial left of it */ airArrayLenSet(LIST(list)->objArr, 0); mids = (double *)airFree(mids); return split; }
int tenGlyphGen(limnObject *glyphsLimn, echoScene *glyphsEcho, tenGlyphParm *parm, const Nrrd *nten, const Nrrd *npos, const Nrrd *nslc) { static const char me[]="tenGlyphGen"; gageShape *shape; airArray *mop; float *tdata, eval[3], evec[9], *cvec, rotEvec[9], mA_f[16], absEval[3], glyphScl[3]; double pI[3], pW[3], cl, cp, sRot[16], mA[16], mB[16], msFr[9], tmpvec[3], R, G, B, qA, qB, qC, glyphAniso, sliceGray; unsigned int duh; int slcCoord[3], idx, glyphIdx, axis, numGlyphs, svRGBAfl=AIR_FALSE; limnLook *look; int lookIdx; echoObject *eglyph, *inst, *list=NULL, *split, *esquare; echoPos_t eM[16], originOffset[3], edge0[3], edge1[3]; char stmp[AIR_STRLEN_SMALL]; /* int eret; double tmp1[3], tmp2[3]; */ if (!( (glyphsLimn || glyphsEcho) && nten && parm)) { biffAddf(TEN, "%s: got NULL pointer", me); return 1; } mop = airMopNew(); shape = gageShapeNew(); shape->defaultCenter = nrrdCenterCell; airMopAdd(mop, shape, (airMopper)gageShapeNix, airMopAlways); if (npos) { if (!( 2 == nten->dim && 7 == nten->axis[0].size )) { biffAddf(TEN, "%s: nten isn't 2-D 7-by-N array", me); airMopError(mop); return 1; } if (!( 2 == npos->dim && 3 == npos->axis[0].size && nten->axis[1].size == npos->axis[1].size )) { biffAddf(TEN, "%s: npos isn't 2-D 3-by-%s array", me, airSprintSize_t(stmp, nten->axis[1].size)); airMopError(mop); return 1; } if (!( nrrdTypeFloat == nten->type && nrrdTypeFloat == npos->type )) { biffAddf(TEN, "%s: nten and npos must be %s, not %s and %s", me, airEnumStr(nrrdType, nrrdTypeFloat), airEnumStr(nrrdType, nten->type), airEnumStr(nrrdType, npos->type)); airMopError(mop); return 1; } } else { if (tenTensorCheck(nten, nrrdTypeFloat, AIR_TRUE, AIR_TRUE)) { biffAddf(TEN, "%s: didn't get a valid DT volume", me); airMopError(mop); return 1; } } if (tenGlyphParmCheck(parm, nten, npos, nslc)) { biffAddf(TEN, "%s: trouble", me); airMopError(mop); return 1; } if (!npos) { if (gageShapeSet(shape, nten, tenGageKind->baseDim)) { biffMovef(TEN, GAGE, "%s: trouble", me); airMopError(mop); return 1; } } if (parm->doSlice) { ELL_3V_COPY(edge0, shape->spacing); ELL_3V_COPY(edge1, shape->spacing); edge0[parm->sliceAxis] = edge1[parm->sliceAxis] = 0.0; switch(parm->sliceAxis) { case 0: edge0[1] = edge1[2] = 0; ELL_4M_ROTATE_Y_SET(sRot, AIR_PI/2); break; case 1: edge0[0] = edge1[2] = 0; ELL_4M_ROTATE_X_SET(sRot, AIR_PI/2); break; case 2: default: edge0[0] = edge1[1] = 0; ELL_4M_IDENTITY_SET(sRot); break; } ELL_3V_COPY(originOffset, shape->spacing); ELL_3V_SCALE(originOffset, -0.5, originOffset); originOffset[parm->sliceAxis] *= -2*parm->sliceOffset; } if (glyphsLimn) { /* create limnLooks for diffuse and ambient-only shading */ /* ??? */ /* hack: save old value of setVertexRGBAFromLook, and set to true */ svRGBAfl = glyphsLimn->setVertexRGBAFromLook; glyphsLimn->setVertexRGBAFromLook = AIR_TRUE; } if (glyphsEcho) { list = echoObjectNew(glyphsEcho, echoTypeList); } if (npos) { numGlyphs = AIR_UINT(nten->axis[1].size); } else { numGlyphs = shape->size[0] * shape->size[1] * shape->size[2]; } /* find measurement frame transform */ if (3 == nten->spaceDim && AIR_EXISTS(nten->measurementFrame[0][0])) { /* msFr nten->measurementFrame ** 0 1 2 [0][0] [1][0] [2][0] ** 3 4 5 [0][1] [1][1] [2][1] ** 6 7 8 [0][2] [1][2] [2][2] */ msFr[0] = nten->measurementFrame[0][0]; msFr[3] = nten->measurementFrame[0][1]; msFr[6] = nten->measurementFrame[0][2]; msFr[1] = nten->measurementFrame[1][0]; msFr[4] = nten->measurementFrame[1][1]; msFr[7] = nten->measurementFrame[1][2]; msFr[2] = nten->measurementFrame[2][0]; msFr[5] = nten->measurementFrame[2][1]; msFr[8] = nten->measurementFrame[2][2]; } else { ELL_3M_IDENTITY_SET(msFr); } for (idx=0; idx<numGlyphs; idx++) { tdata = (float*)(nten->data) + 7*idx; if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: hello %g %g %g %g %g %g %g\n", me, idx, numGlyphs, tdata[0], tdata[1], tdata[2], tdata[3], tdata[4], tdata[5], tdata[6]); } if (!( TEN_T_EXISTS(tdata) )) { /* there's nothing we can do here */ if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: non-existent data\n", me, idx, numGlyphs); } continue; } if (npos) { ELL_3V_COPY(pW, (float*)(npos->data) + 3*idx); if (!( AIR_EXISTS(pW[0]) && AIR_EXISTS(pW[1]) && AIR_EXISTS(pW[2]) )) { /* position doesn't exist- perhaps because its from the push library, which might kill points by setting coords to nan */ continue; } } else { NRRD_COORD_GEN(pI, shape->size, 3, idx); /* this does take into account full orientation */ gageShapeItoW(shape, pW, pI); if (parm->nmask) { if (!( nrrdFLookup[parm->nmask->type](parm->nmask->data, idx) >= parm->maskThresh )) { if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: doesn't meet mask thresh\n", me, idx, numGlyphs); } continue; } } } tenEigensolve_f(eval, evec, tdata); /* transform eigenvectors by measurement frame */ ELL_3MV_MUL(tmpvec, msFr, evec + 0); ELL_3V_COPY_TT(evec + 0, float, tmpvec); ELL_3MV_MUL(tmpvec, msFr, evec + 3); ELL_3V_COPY_TT(evec + 3, float, tmpvec); ELL_3MV_MUL(tmpvec, msFr, evec + 6); ELL_3V_COPY_TT(evec + 6, float, tmpvec); ELL_3V_CROSS(tmpvec, evec + 0, evec + 3); if (0 > ELL_3V_DOT(tmpvec, evec + 6)) { ELL_3V_SCALE(evec + 6, -1, evec + 6); } ELL_3M_TRANSPOSE(rotEvec, evec); if (parm->doSlice && pI[parm->sliceAxis] == parm->slicePos) { /* set sliceGray */ if (nslc) { /* we aren't masked by confidence, as anisotropy slice is */ for (duh=0; duh<parm->sliceAxis; duh++) { slcCoord[duh] = (int)(pI[duh]); } for (duh=duh<parm->sliceAxis; duh<2; duh++) { slcCoord[duh] = (int)(pI[duh+1]); } /* HEY: GLK has no idea what's going here */ slcCoord[0] = (int)(pI[0]); slcCoord[1] = (int)(pI[1]); slcCoord[2] = (int)(pI[2]); sliceGray = nrrdFLookup[nslc->type](nslc->data, slcCoord[0] + nslc->axis[0].size*slcCoord[1]); } else { if (!( tdata[0] >= parm->confThresh )) { if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d (slice): conf %g < thresh %g\n", me, idx, numGlyphs, tdata[0], parm->confThresh); } continue; } sliceGray = tenAnisoEval_f(eval, parm->sliceAnisoType); } if (parm->sliceGamma > 0) { sliceGray = AIR_AFFINE(0, sliceGray, 1, parm->sliceBias, 1); sliceGray = pow(sliceGray, 1.0/parm->sliceGamma); } else { sliceGray = AIR_AFFINE(0, sliceGray, 1, 0, 1-parm->sliceBias); sliceGray = 1.0 - pow(sliceGray, -1.0/parm->sliceGamma); } /* make slice contribution */ /* HEY: this is *NOT* aware of shape->fromOrientation */ if (glyphsLimn) { lookIdx = limnObjectLookAdd(glyphsLimn); look = glyphsLimn->look + lookIdx; ELL_4V_SET_TT(look->rgba, float, sliceGray, sliceGray, sliceGray, 1); ELL_3V_SET(look->kads, 1, 0, 0); look->spow = 0; glyphIdx = limnObjectSquareAdd(glyphsLimn, lookIdx); ELL_4M_IDENTITY_SET(mA); ell_4m_post_mul_d(mA, sRot); if (!npos) { ELL_4M_SCALE_SET(mB, shape->spacing[0], shape->spacing[1], shape->spacing[2]); } ell_4m_post_mul_d(mA, mB); ELL_4M_TRANSLATE_SET(mB, pW[0], pW[1], pW[2]); ell_4m_post_mul_d(mA, mB); ELL_4M_TRANSLATE_SET(mB, originOffset[0], originOffset[1], originOffset[2]); ell_4m_post_mul_d(mA, mB); ELL_4M_COPY_TT(mA_f, float, mA); limnObjectPartTransform(glyphsLimn, glyphIdx, mA_f); } if (glyphsEcho) { esquare = echoObjectNew(glyphsEcho,echoTypeRectangle); ELL_3V_ADD2(((echoRectangle*)esquare)->origin, pW, originOffset); ELL_3V_COPY(((echoRectangle*)esquare)->edge0, edge0); ELL_3V_COPY(((echoRectangle*)esquare)->edge1, edge1); echoColorSet(esquare, AIR_CAST(echoCol_t, sliceGray), AIR_CAST(echoCol_t, sliceGray), AIR_CAST(echoCol_t, sliceGray), 1); /* this is pretty arbitrary- but I want shadows to have some effect. Previously, the material was all ambient: (A,D,S) = (1,0,0), which avoided all shadow effects. */ echoMatterPhongSet(glyphsEcho, esquare, 0.4f, 0.6f, 0, 40); echoListAdd(list, esquare); } } if (parm->onlyPositive) { if (eval[2] < 0) { /* didn't have all positive eigenvalues, its outta here */ if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: not all evals %g %g %g > 0\n", me, idx, numGlyphs, eval[0], eval[1], eval[2]); } continue; } } if (!( tdata[0] >= parm->confThresh )) { if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: conf %g < thresh %g\n", me, idx, numGlyphs, tdata[0], parm->confThresh); } continue; } if (!( tenAnisoEval_f(eval, parm->anisoType) >= parm->anisoThresh )) { if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: aniso[%d] %g < thresh %g\n", me, idx, numGlyphs, parm->anisoType, tenAnisoEval_f(eval, parm->anisoType), parm->anisoThresh); } continue; } glyphAniso = tenAnisoEval_f(eval, parm->colAnisoType); /* fprintf(stderr, "%s: eret = %d; evals = %g %g %g\n", me, eret, eval[0], eval[1], eval[2]); ELL_3V_CROSS(tmp1, evec+0, evec+3); tmp2[0] = ELL_3V_LEN(tmp1); ELL_3V_CROSS(tmp1, evec+0, evec+6); tmp2[1] = ELL_3V_LEN(tmp1); ELL_3V_CROSS(tmp1, evec+3, evec+6); tmp2[2] = ELL_3V_LEN(tmp1); fprintf(stderr, "%s: crosses = %g %g %g\n", me, tmp2[0], tmp2[1], tmp2[2]); */ /* set transform (in mA) */ ELL_3V_ABS(absEval, eval); ELL_4M_IDENTITY_SET(mA); /* reset */ ELL_3V_SCALE(glyphScl, parm->glyphScale, absEval); /* scale by evals */ ELL_4M_SCALE_SET(mB, glyphScl[0], glyphScl[1], glyphScl[2]); ell_4m_post_mul_d(mA, mB); ELL_43M_INSET(mB, rotEvec); /* rotate by evecs */ ell_4m_post_mul_d(mA, mB); ELL_4M_TRANSLATE_SET(mB, pW[0], pW[1], pW[2]); /* translate */ ell_4m_post_mul_d(mA, mB); /* set color (in R,G,B) */ cvec = evec + 3*(AIR_CLAMP(0, parm->colEvec, 2)); R = AIR_ABS(cvec[0]); /* standard mapping */ G = AIR_ABS(cvec[1]); B = AIR_ABS(cvec[2]); /* desaturate by colMaxSat */ R = AIR_AFFINE(0.0, parm->colMaxSat, 1.0, parm->colIsoGray, R); G = AIR_AFFINE(0.0, parm->colMaxSat, 1.0, parm->colIsoGray, G); B = AIR_AFFINE(0.0, parm->colMaxSat, 1.0, parm->colIsoGray, B); /* desaturate some by anisotropy */ R = AIR_AFFINE(0.0, parm->colAnisoModulate, 1.0, R, AIR_AFFINE(0.0, glyphAniso, 1.0, parm->colIsoGray, R)); G = AIR_AFFINE(0.0, parm->colAnisoModulate, 1.0, G, AIR_AFFINE(0.0, glyphAniso, 1.0, parm->colIsoGray, G)); B = AIR_AFFINE(0.0, parm->colAnisoModulate, 1.0, B, AIR_AFFINE(0.0, glyphAniso, 1.0, parm->colIsoGray, B)); /* clamp and do gamma */ R = AIR_CLAMP(0.0, R, 1.0); G = AIR_CLAMP(0.0, G, 1.0); B = AIR_CLAMP(0.0, B, 1.0); R = pow(R, parm->colGamma); G = pow(G, parm->colGamma); B = pow(B, parm->colGamma); /* find axis, and superquad exponents qA and qB */ if (eval[2] > 0) { /* all evals positive */ cl = AIR_MIN(0.99, tenAnisoEval_f(eval, tenAniso_Cl1)); cp = AIR_MIN(0.99, tenAnisoEval_f(eval, tenAniso_Cp1)); if (cl > cp) { axis = 0; qA = pow(1-cp, parm->sqdSharp); qB = pow(1-cl, parm->sqdSharp); } else { axis = 2; qA = pow(1-cl, parm->sqdSharp); qB = pow(1-cp, parm->sqdSharp); } qC = qB; } else if (eval[0] < 0) { /* all evals negative */ float aef[3]; aef[0] = absEval[2]; aef[1] = absEval[1]; aef[2] = absEval[0]; cl = AIR_MIN(0.99, tenAnisoEval_f(aef, tenAniso_Cl1)); cp = AIR_MIN(0.99, tenAnisoEval_f(aef, tenAniso_Cp1)); if (cl > cp) { axis = 2; qA = pow(1-cp, parm->sqdSharp); qB = pow(1-cl, parm->sqdSharp); } else { axis = 0; qA = pow(1-cl, parm->sqdSharp); qB = pow(1-cp, parm->sqdSharp); } qC = qB; } else { #define OOSQRT2 0.70710678118654752440 #define OOSQRT3 0.57735026918962576451 /* double poleA[3]={OOSQRT3, OOSQRT3, OOSQRT3}; */ double poleB[3]={1, 0, 0}; double poleC[3]={OOSQRT2, OOSQRT2, 0}; double poleD[3]={OOSQRT3, -OOSQRT3, -OOSQRT3}; double poleE[3]={OOSQRT2, 0, -OOSQRT2}; double poleF[3]={OOSQRT3, OOSQRT3, -OOSQRT3}; double poleG[3]={0, -OOSQRT2, -OOSQRT2}; double poleH[3]={0, 0, -1}; /* double poleI[3]={-OOSQRT3, -OOSQRT3, -OOSQRT3}; */ double funk[3]={0,4,2}, thrn[3]={1,4,4}; double octa[3]={0,2,2}, cone[3]={1,2,2}; double evalN[3], tmp, bary[3]; double qq[3]; ELL_3V_NORM(evalN, eval, tmp); if (eval[1] >= -eval[2]) { /* inside B-F-C */ ell_3v_barycentric_spherical_d(bary, poleB, poleF, poleC, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], octa, bary[1], thrn, bary[2], cone); axis = 2; } else if (eval[0] >= -eval[2]) { /* inside B-D-F */ if (eval[1] >= 0) { /* inside B-E-F */ ell_3v_barycentric_spherical_d(bary, poleB, poleE, poleF, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], octa, bary[1], funk, bary[2], thrn); axis = 2; } else { /* inside B-D-E */ ell_3v_barycentric_spherical_d(bary, poleB, poleD, poleE, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], cone, bary[1], thrn, bary[2], funk); axis = 0; } } else if (eval[0] < -eval[1]) { /* inside D-G-H */ ell_3v_barycentric_spherical_d(bary, poleD, poleG, poleH, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], thrn, bary[1], cone, bary[2], octa); axis = 0; } else if (eval[1] < 0) { /* inside E-D-H */ ell_3v_barycentric_spherical_d(bary, poleE, poleD, poleH, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], funk, bary[1], thrn, bary[2], octa); axis = 0; } else { /* inside F-E-H */ ell_3v_barycentric_spherical_d(bary, poleF, poleE, poleH, evalN); ELL_3V_SCALE_ADD3(qq, bary[0], thrn, bary[1], funk, bary[2], cone); axis = 2; } qA = qq[0]; qB = qq[1]; qC = qq[2]; #undef OOSQRT2 #undef OOSQRT3 } /* add the glyph */ if (parm->verbose >= 2) { fprintf(stderr, "%s: glyph %d/%d: the glyph stays!\n", me, idx, numGlyphs); } if (glyphsLimn) { lookIdx = limnObjectLookAdd(glyphsLimn); look = glyphsLimn->look + lookIdx; ELL_4V_SET_TT(look->rgba, float, R, G, B, 1); ELL_3V_SET(look->kads, parm->ADSP[0], parm->ADSP[1], parm->ADSP[2]); look->spow = 0; switch(parm->glyphType) { case tenGlyphTypeBox: glyphIdx = limnObjectCubeAdd(glyphsLimn, lookIdx); break; case tenGlyphTypeSphere: glyphIdx = limnObjectPolarSphereAdd(glyphsLimn, lookIdx, axis, 2*parm->facetRes, parm->facetRes); break; case tenGlyphTypeCylinder: glyphIdx = limnObjectCylinderAdd(glyphsLimn, lookIdx, axis, parm->facetRes); break; case tenGlyphTypeSuperquad: default: glyphIdx = limnObjectPolarSuperquadFancyAdd(glyphsLimn, lookIdx, axis, AIR_CAST(float, qA), AIR_CAST(float, qB), AIR_CAST(float, qC), 0, 2*parm->facetRes, parm->facetRes); break; } ELL_4M_COPY_TT(mA_f, float, mA); limnObjectPartTransform(glyphsLimn, glyphIdx, mA_f); } if (glyphsEcho) { switch(parm->glyphType) { case tenGlyphTypeBox: eglyph = echoObjectNew(glyphsEcho, echoTypeCube); /* nothing else to set */ break; case tenGlyphTypeSphere: eglyph = echoObjectNew(glyphsEcho, echoTypeSphere); echoSphereSet(eglyph, 0, 0, 0, 1); break; case tenGlyphTypeCylinder: eglyph = echoObjectNew(glyphsEcho, echoTypeCylinder); echoCylinderSet(eglyph, axis); break; case tenGlyphTypeSuperquad: default: eglyph = echoObjectNew(glyphsEcho, echoTypeSuperquad); echoSuperquadSet(eglyph, axis, qA, qB); break; } echoColorSet(eglyph, AIR_CAST(echoCol_t, R), AIR_CAST(echoCol_t, G), AIR_CAST(echoCol_t, B), 1); echoMatterPhongSet(glyphsEcho, eglyph, parm->ADSP[0], parm->ADSP[1], parm->ADSP[2], parm->ADSP[3]); inst = echoObjectNew(glyphsEcho, echoTypeInstance); ELL_4M_COPY(eM, mA); echoInstanceSet(inst, eM, eglyph); echoListAdd(list, inst); } } if (glyphsLimn) { glyphsLimn->setVertexRGBAFromLook = svRGBAfl; } if (glyphsEcho) { split = echoListSplit3(glyphsEcho, list, 10); echoObjectAdd(glyphsEcho, split); } airMopOkay(mop); return 0; }
void tenGlyphBqdAbcUv(double abc[3], const double uv[2], double betaMax) { static const unsigned int vertsZone[10][3] = {{0, 1, 2}, /* 0 */ {0, 2, 3}, /* 1 */ {1, 3, 4}, /* 2 */ {1, 4, 5}, /* 3 */ {4, 5, 9}, /* 4 */ {1, 5, 6}, /* 5 */ {5, 6, 9}, /* 6 */ {6, 7, 9}, /* 7 */ {7, 8, 10}, /* 8 */ {8, 9, 10}}; /* 9 */ static const double uvVert[11][2] = {{1.00, 1.00}, /* 0 */ {0.50, 1.00}, /* 1 */ {0.75, 0.75}, /* 2 */ {1.00, 0.50}, /* 3 */ {1.00, 0.00}, /* 4 */ {0.50, 0.50}, /* 5 */ {0.00, 1.00}, /* 6 */ {0.00, 0.50}, /* 7 */ {0.25, 0.25}, /* 8 */ {0.50, 0.00}, /* 9 */ {0.00, 0.00}}; /* 10 */ double abcBall[3], abcCyli[3], abcFunk[3], abcThrn[3], abcOcta[3], abcCone[3], abcHalf[3]; /* old compile-time setting const double *abcAll[10][11] = { zone \ vert 0 1 2 3 4 5 6 7 8 9 10 0 {abcBall, abcCyli, abcHalf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, 1 {abcBall, NULL, abcHalf, abcCyli, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, 2 { NULL, abcOcta, NULL, abcCone, abcThrn, NULL, NULL, NULL, NULL, NULL, NULL }, 3 { NULL, abcOcta, NULL, NULL, abcThrn, abcFunk, NULL, NULL, NULL, NULL, NULL }, 4 { NULL, NULL, NULL, NULL, abcThrn, abcFunk, NULL, NULL, NULL, abcCone, NULL }, 5 { NULL, abcCone, NULL, NULL, NULL, abcFunk, abcThrn, NULL, NULL, NULL, NULL }, 6 { NULL, NULL, NULL, NULL, NULL, abcFunk, abcThrn, NULL, NULL, abcOcta, NULL }, 7 { NULL, NULL, NULL, NULL, NULL, NULL, abcThrn, abcCone, NULL, abcOcta, NULL }, 8 { NULL, NULL, NULL, NULL, NULL, NULL, NULL, abcCyli, abcHalf, NULL, abcBall }, 9 { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, abcHalf, abcCyli, abcBall }}; */ const double *abcAll[10][11]; unsigned int pvi[3], zone, vert; double bcoord[3]; ELL_3V_SET(abcBall, 1, 1, 1); ELL_3V_SET(abcCyli, 1, 0, 0); ELL_3V_SET(abcFunk, 0, betaMax, 2); /* only one with c != b */ ELL_3V_SET(abcThrn, 1, betaMax, 3); ELL_3V_SET(abcOcta, 0, 2, 2); ELL_3V_SET(abcCone, 1, 2, 2); ELL_3V_SET(abcHalf, 0.5, 0.5, 0.5); /* alpha is half-way between alpha of octa and cone and beta has to be the same as alpha at for the seam to be shape-continuous */ /* run-time setting of abcAll[][]; compile-time setting (comments above) gives "initializer element is not computable at load time" warnings */ for (zone=0; zone<10; zone++) { for (vert=0; vert<11; vert++) { abcAll[zone][vert]=NULL; } } #define SET(zi, vi0, vi1, vi2, sh0, sh1, sh2) \ abcAll[zi][vi0] = abc##sh0; \ abcAll[zi][vi1] = abc##sh1; \ abcAll[zi][vi2] = abc##sh2 SET(0, 0, 1, 2, Ball, Cyli, Half); SET(1, 0, 2, 3, Ball, Half, Cyli); SET(2, 1, 3, 4, Octa, Cone, Thrn); SET(3, 1, 4, 5, Octa, Thrn, Funk); SET(4, 4, 5, 9, Thrn, Funk, Cone); SET(5, 1, 5, 6, Cone, Funk, Thrn); SET(6, 5, 6, 9, Funk, Thrn, Octa); SET(7, 6, 7, 9, Thrn, Cone, Octa); SET(8, 7, 8,10, Cyli, Half, Ball); SET(9, 8, 9,10, Half, Cyli, Ball); #undef SET zone = tenGlyphBqdZoneUv(uv); ELL_3V_COPY(pvi, vertsZone[zone]); baryFind(bcoord, uv, uvVert[pvi[0]], uvVert[pvi[1]], uvVert[pvi[2]]); baryBlend(abc, bcoord, abcAll[zone][pvi[0]], abcAll[zone][pvi[1]], abcAll[zone][pvi[2]]); return; }