void _ra2t(Nrrd *nten, double rad, double angle, double mRI[9], double mRF[9], double hack) { double x, y, xyz[3], XX[3], YY[3], CC[3], EE[3], VV[3], tmp, mD[9], mT[9]; float *tdata; int xi, yi, sx, sy; sx = nten->axis[1].size; sy = nten->axis[2].size; x = rad*sin(AIR_PI*angle/180); y = rad*cos(AIR_PI*angle/180); xi = airIndexClamp(0.0, x, sqrt(3.0)/2.0, sx); yi = airIndexClamp(0.0, y, 0.5, sy); ELL_3V_SET(VV, 0, 3, 0); ELL_3V_SET(EE, 1.5, 1.5, 0); ELL_3V_SET(CC, 1, 1, 1); ELL_3V_SUB(YY, EE, CC); ELL_3V_SUB(XX, VV, EE); ELL_3V_NORM(XX, XX, tmp); ELL_3V_NORM(YY, YY, tmp); ELL_3V_SCALE_ADD3(xyz, 1.0, CC, hack*x, XX, hack*y, YY); ELL_3M_IDENTITY_SET(mD); ELL_3M_DIAG_SET(mD, xyz[0], xyz[1], xyz[2]); ELL_3M_IDENTITY_SET(mT); ell_3m_post_mul_d(mT, mRI); ell_3m_post_mul_d(mT, mD); ell_3m_post_mul_d(mT, mRF); tdata = (float*)(nten->data) + 7*(xi + sx*(yi + 1*sy)); tdata[0] = 1.0; TEN_M2T(tdata, mT); }
int main(int argc, const char *argv[]) { const char *me; char *err, *outS; hestOpt *hopt=NULL; airArray *mop; int xi, yi, zi, samp; float *tdata; double clp[2], xyz[3], q[4], len; double mD[9], mRF[9], mRI[9], mT[9]; Nrrd *nten; mop = airMopNew(); me = argv[0]; hestOptAdd(&hopt, "n", "# samples", airTypeInt, 1, 1, &samp, "4", "number of samples along each edge of cube"); hestOptAdd(&hopt, "c", "cl cp", airTypeDouble, 2, 2, clp, NULL, "shape of tensor to use; \"cl\" and \"cp\" are cl1 " "and cp1 values, both in [0.0,1.0]"); hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-", "output file to save tensors into"); 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); nten = nrrdNew(); airMopAdd(mop, nten, (airMopper)nrrdNuke, airMopAlways); _clp2xyz(xyz, clp); fprintf(stderr, "%s: want evals = %g %g %g\n", me, xyz[0], xyz[1], xyz[2]); if (nrrdMaybeAlloc_va(nten, nrrdTypeFloat, 4, AIR_CAST(size_t, 7), AIR_CAST(size_t, samp), AIR_CAST(size_t, samp), AIR_CAST(size_t, samp))) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: couldn't allocate output:\n%s\n", me, err); airMopError(mop); return 1; } ELL_3M_IDENTITY_SET(mD); ELL_3M_DIAG_SET(mD, xyz[0], xyz[1], xyz[2]); tdata = (float*)nten->data; for (zi=0; zi<samp; zi++) { for (yi=0; yi<samp; yi++) { for (xi=0; xi<samp; xi++) { q[0] = 1.0; q[1] = AIR_AFFINE(-0.5, (float)xi, samp-0.5, -1, 1); q[2] = AIR_AFFINE(-0.5, (float)yi, samp-0.5, -1, 1); q[3] = AIR_AFFINE(-0.5, (float)zi, samp-0.5, -1, 1); len = ELL_4V_LEN(q); ELL_4V_SCALE(q, 1.0/len, q); washQtoM3(mRF, q); ELL_3M_TRANSPOSE(mRI, mRF); ELL_3M_IDENTITY_SET(mT); ell_3m_post_mul_d(mT, mRI); ell_3m_post_mul_d(mT, mD); ell_3m_post_mul_d(mT, mRF); tdata[0] = 1.0; TEN_M2T(tdata, mT); tdata += 7; } } } if (nrrdSave(outS, nten, NULL)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: couldn't save output:\n%s\n", me, err); airMopError(mop); return 1; } airMopOkay(mop); return 0; }
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; }
void _ell_3m_evecs_d(double evec[9], double eval[3], int roots, const double m[9]) { double n[9], e0=0, e1=0.0, e2=0.0, t /* , tmpv[3] */ ; ELL_3V_GET(e0, e1, e2, eval); /* if (ell_debug) { printf("ell_3m_evecs_d: numroots = %d\n", numroots); } */ /* we form m - lambda*I by doing a memcpy from m, and then (repeatedly) over-writing the diagonal elements */ ELL_3M_COPY(n, m); switch (roots) { case ell_cubic_root_three: /* if (ell_debug) { printf("ell_3m_evecs_d: evals: %20.15f %20.15f %20.15f\n", eval[0], eval[1], eval[2]); } */ ELL_3M_DIAG_SET(n, m[0]-e0, m[4]-e0, m[8]-e0); ell_3m_1d_nullspace_d(evec+0, n); ELL_3M_DIAG_SET(n, m[0]-e1, m[4]-e1, m[8]-e1); ell_3m_1d_nullspace_d(evec+3, n); ELL_3M_DIAG_SET(n, m[0]-e2, m[4]-e2, m[8]-e2); ell_3m_1d_nullspace_d(evec+6, n); _ell_3m_enforce_orthogonality(evec); _ell_3m_make_right_handed_d(evec); ELL_3V_SET(eval, e0, e1, e2); break; case ell_cubic_root_single_double: ELL_SORT3(e0, e1, e2, t); if (e0 > e1) { /* one big (e0) , two small (e1, e2) : more like a cigar */ ELL_3M_DIAG_SET(n, m[0]-e0, m[4]-e0, m[8]-e0); ell_3m_1d_nullspace_d(evec+0, n); ELL_3M_DIAG_SET(n, m[0]-e1, m[4]-e1, m[8]-e1); ell_3m_2d_nullspace_d(evec+3, evec+6, n); } else { /* two big (e0, e1), one small (e2): more like a pancake */ ELL_3M_DIAG_SET(n, m[0]-e0, m[4]-e0, m[8]-e0); ell_3m_2d_nullspace_d(evec+0, evec+3, n); ELL_3M_DIAG_SET(n, m[0]-e2, m[4]-e2, m[8]-e2); ell_3m_1d_nullspace_d(evec+6, n); } _ell_3m_enforce_orthogonality(evec); _ell_3m_make_right_handed_d(evec); ELL_3V_SET(eval, e0, e1, e2); break; case ell_cubic_root_triple: /* one triple root; use any basis as the eigenvectors */ ELL_3V_SET(evec+0, 1, 0, 0); ELL_3V_SET(evec+3, 0, 1, 0); ELL_3V_SET(evec+6, 0, 0, 1); ELL_3V_SET(eval, e0, e1, e2); break; case ell_cubic_root_single: /* only one real root */ ELL_3M_DIAG_SET(n, m[0]-e0, m[4]-e0, m[8]-e0); ell_3m_1d_nullspace_d(evec+0, n); ELL_3V_SET(evec+3, AIR_NAN, AIR_NAN, AIR_NAN); ELL_3V_SET(evec+6, AIR_NAN, AIR_NAN, AIR_NAN); ELL_3V_SET(eval, e0, AIR_NAN, AIR_NAN); break; } /* if (ell_debug) { printf("ell_3m_evecs_d (numroots = %d): evecs: \n", numroots); ELL_3MV_MUL(tmpv, m, evec[0]); printf(" (%g:%g): %20.15f %20.15f %20.15f\n", eval[0], ELL_3V_DOT(evec[0], tmpv), evec[0][0], evec[0][1], evec[0][2]); ELL_3MV_MUL(tmpv, m, evec[1]); printf(" (%g:%g): %20.15f %20.15f %20.15f\n", eval[1], ELL_3V_DOT(evec[1], tmpv), evec[1][0], evec[1][1], evec[1][2]); ELL_3MV_MUL(tmpv, m, evec[2]); printf(" (%g:%g): %20.15f %20.15f %20.15f\n", eval[2], ELL_3V_DOT(evec[2], tmpv), evec[2][0], evec[2][1], evec[2][2]); } */ return; }
void _gageSclAnswer (gageContext *ctx, gagePerVolume *pvl) { char me[]="_gageSclAnswer"; double gmag=0, *hess, *norm, *gvec, *gten, *k1, *k2, curv=0, sHess[9]={0,0,0,0,0,0,0,0,0}; double tmpMat[9], tmpVec[3], hevec[9], heval[3]; double len, gp1[3], gp2[3], *nPerp, ncTen[9], nProj[9]={0,0,0,0,0,0,0,0,0}; double alpha = 0.5; double beta = 0.5; double gamma = 5; double cc = 1e-6; #define FD_MEDIAN_MAX 16 int fd, nidx, xi, yi, zi; double *fw, iv3wght[2*FD_MEDIAN_MAX*FD_MEDIAN_MAX*FD_MEDIAN_MAX], wghtSum, wght; /* convenience pointers for work below */ hess = pvl->directAnswer[gageSclHessian]; gvec = pvl->directAnswer[gageSclGradVec]; norm = pvl->directAnswer[gageSclNormal]; nPerp = pvl->directAnswer[gageSclNPerp]; gten = pvl->directAnswer[gageSclGeomTens]; k1 = pvl->directAnswer[gageSclK1]; k2 = pvl->directAnswer[gageSclK2]; if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclValue)) { /* done if doV */ if (ctx->verbose) { fprintf(stderr, "%s: val = % 15.7f\n", me, (double)(pvl->directAnswer[gageSclValue][0])); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGradVec)) { /* done if doD1 */ if (ctx->verbose) { fprintf(stderr, "%s: gvec = ", me); ell_3v_print_d(stderr, gvec); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGradMag)) { /* this is the true value of gradient magnitude */ gmag = pvl->directAnswer[gageSclGradMag][0] = sqrt(ELL_3V_DOT(gvec, gvec)); } /* NB: it would seem that gageParmGradMagMin is completely ignored ... */ if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclNormal)) { if (gmag) { ELL_3V_SCALE(norm, 1/gmag, gvec); /* polishing ... len = sqrt(ELL_3V_DOT(norm, norm)); ELL_3V_SCALE(norm, 1/len, norm); */ } else { ELL_3V_COPY(norm, gageZeroNormal); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclNPerp)) { /* nPerp = I - outer(norm, norm) */ /* NB: this sets both nPerp and nProj */ ELL_3MV_OUTER(nProj, norm, norm); ELL_3M_SCALE(nPerp, -1, nProj); nPerp[0] += 1; nPerp[4] += 1; nPerp[8] += 1; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessian)) { /* done if doD2 */ if (ctx->verbose) { fprintf(stderr, "%s: hess = \n", me); ell_3m_print_d(stderr, hess); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclLaplacian)) { pvl->directAnswer[gageSclLaplacian][0] = hess[0] + hess[4] + hess[8]; if (ctx->verbose) { fprintf(stderr, "%s: lapl = %g + %g + %g = %g\n", me, hess[0], hess[4], hess[8], pvl->directAnswer[gageSclLaplacian][0]); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessFrob)) { pvl->directAnswer[gageSclHessFrob][0] = ELL_3M_FROB(hess); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessEval)) { /* HEY: look at the return value for root multiplicity? */ ell_3m_eigensolve_d(heval, hevec, hess, AIR_TRUE); ELL_3V_COPY(pvl->directAnswer[gageSclHessEval], heval); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessEvec)) { ELL_3M_COPY(pvl->directAnswer[gageSclHessEvec], hevec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessRidgeness)) { double A, B, S; if (heval[1] >0 || heval[2]>0) { pvl->directAnswer[gageSclHessRidgeness][0] = 0; } else if (AIR_ABS(heval[1])<1e-10 || AIR_ABS(heval[2])<1e-10) { pvl->directAnswer[gageSclHessRidgeness][0] = 0; } else { double *ans; A = AIR_ABS(heval[1])/AIR_ABS(heval[2]); B = AIR_ABS(heval[0])/sqrt(AIR_ABS(heval[1]*heval[2])); S = sqrt(heval[0]*heval[0] + heval[1]*heval[1] + heval[2]*heval[2]); ans = pvl->directAnswer[gageSclHessRidgeness]; ans[0] = (1-exp(-A*A/(2*alpha*alpha))) * exp(-B*B/(2*beta*beta)) * (1-exp(-S*S/(2*gamma*gamma))) * exp(-2*cc*cc/(AIR_ABS(heval[1])*heval[2]*heval[2])); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessValleyness)) { double A, B, S; if (heval[0] <0 || heval[1]<0) { pvl->directAnswer[gageSclHessValleyness][0] = 0; } else if (AIR_ABS(heval[0])<1e-10 || AIR_ABS(heval[1])<1e-10) { pvl->directAnswer[gageSclHessValleyness][0] = 0; } else { double *ans; A = AIR_ABS(heval[1])/AIR_ABS(heval[0]); B = AIR_ABS(heval[2])/sqrt(AIR_ABS(heval[1]*heval[0])); S = sqrt(heval[0]*heval[0] + heval[1]*heval[1] + heval[2]*heval[2]); ans = pvl->directAnswer[gageSclHessValleyness]; ans[0] = (1-exp(-A*A/(2*alpha*alpha))) * exp(-B*B/(2*beta*beta)) * (1-exp(-S*S/(2*gamma*gamma))) * exp(-2*cc*cc/(AIR_ABS(heval[1])*heval[0]*heval[0])); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessMode)) { pvl->directAnswer[gageSclHessMode][0] = airMode3_d(heval); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageScl2ndDD)) { ELL_3MV_MUL(tmpVec, hess, norm); pvl->directAnswer[gageScl2ndDD][0] = ELL_3V_DOT(norm, tmpVec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGeomTens)) { if (gmag > ctx->parm.gradMagCurvMin) { /* parm.curvNormalSide applied here to determine the sense of the normal when doing all curvature calculations */ ELL_3M_SCALE(sHess, -(ctx->parm.curvNormalSide)/gmag, hess); /* gten = nPerp * sHess * nPerp */ ELL_3M_MUL(tmpMat, sHess, nPerp); ELL_3M_MUL(gten, nPerp, tmpMat); if (ctx->verbose) { fprintf(stderr, "%s: gten: \n", me); ell_3m_print_d(stderr, gten); ELL_3MV_MUL(tmpVec, gten, norm); len = ELL_3V_LEN(tmpVec); fprintf(stderr, "%s: should be small: %30.15f\n", me, (double)len); ell_3v_perp_d(gp1, norm); ELL_3MV_MUL(tmpVec, gten, gp1); len = ELL_3V_LEN(tmpVec); fprintf(stderr, "%s: should be bigger: %30.15f\n", me, (double)len); ELL_3V_CROSS(gp2, gp1, norm); ELL_3MV_MUL(tmpVec, gten, gp2); len = ELL_3V_LEN(tmpVec); fprintf(stderr, "%s: should (also) be bigger: %30.15f\n", me, (double)len); } } else { ELL_3M_ZERO_SET(gten); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclTotalCurv)) { curv = pvl->directAnswer[gageSclTotalCurv][0] = ELL_3M_FROB(gten); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclShapeTrace)) { pvl->directAnswer[gageSclShapeTrace][0] = (curv ? ELL_3M_TRACE(gten)/curv : 0); } if ( (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclK1)) || (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclK2)) ){ double T, N, D; T = ELL_3M_TRACE(gten); N = curv; D = 2*N*N - T*T; /* if (D < -0.0000001) { fprintf(stderr, "%s: %g %g\n", me, T, N); fprintf(stderr, "%s: !!! D curv determinant % 22.10f < 0.0\n", me, D); fprintf(stderr, "%s: gten: \n", me); ell_3m_print_d(stderr, gten); } */ D = AIR_MAX(D, 0); D = sqrt(D); k1[0] = 0.5*(T + D); k2[0] = 0.5*(T - D); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclMeanCurv)) { pvl->directAnswer[gageSclMeanCurv][0] = (*k1 + *k2)/2; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGaussCurv)) { pvl->directAnswer[gageSclGaussCurv][0] = (*k1)*(*k2); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclShapeIndex)) { pvl->directAnswer[gageSclShapeIndex][0] = -(2/AIR_PI)*atan2(*k1 + *k2, *k1 - *k2); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclCurvDir1)) { /* HEY: this only works when K1, K2, 0 are all well mutually distinct, since these are the eigenvalues of the geometry tensor, and this code assumes that the eigenspaces are all one-dimensional */ ELL_3M_COPY(tmpMat, gten); ELL_3M_DIAG_SET(tmpMat, gten[0] - *k1, gten[4]- *k1, gten[8] - *k1); ell_3m_1d_nullspace_d(tmpVec, tmpMat); ELL_3V_COPY(pvl->directAnswer[gageSclCurvDir1], tmpVec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclCurvDir2)) { /* HEY: this only works when K1, K2, 0 are all well mutually distinct, since these are the eigenvalues of the geometry tensor, and this code assumes that the eigenspaces are all one-dimensional */ ELL_3M_COPY(tmpMat, gten); ELL_3M_DIAG_SET(tmpMat, gten[0] - *k2, gten[4] - *k2, gten[8] - *k2); ell_3m_1d_nullspace_d(tmpVec, tmpMat); ELL_3V_COPY(pvl->directAnswer[gageSclCurvDir2], tmpVec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclFlowlineCurv)) { if (gmag >= ctx->parm.gradMagCurvMin) { /* because of the gageSclGeomTens prerequisite, sHess, nPerp, and nProj are all already set */ /* ncTen = nPerp * sHess * nProj */ ELL_3M_MUL(tmpMat, sHess, nProj); ELL_3M_MUL(ncTen, nPerp, tmpMat); } else { ELL_3M_ZERO_SET(ncTen); } /* there used to be a wrong extra sqrt() here */ pvl->directAnswer[gageSclFlowlineCurv][0] = ELL_3M_FROB(ncTen); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclMedian)) { /* this item is currently a complete oddball in that it does not benefit from anything done in the "filter" stage, which is in fact a waste of time if the query consists only of this item */ fd = 2*ctx->radius; if (fd > FD_MEDIAN_MAX) { fprintf(stderr, "%s: PANIC: current filter diameter = %d " "> FD_MEDIAN_MAX = %d\n", me, fd, FD_MEDIAN_MAX); exit(1); } fw = ctx->fw + fd*3*gageKernel00; /* HEY: this needs some optimization help */ wghtSum = 0; nidx = 0; for (xi=0; xi<fd; xi++) { for (yi=0; yi<fd; yi++) { for (zi=0; zi<fd; zi++) { iv3wght[0 + 2*nidx] = pvl->iv3[nidx]; iv3wght[1 + 2*nidx] = fw[xi + 0*fd]*fw[yi + 1*fd]*fw[zi + 2*fd]; wghtSum += iv3wght[1 + 2*nidx]; nidx++; } } } qsort(iv3wght, fd*fd*fd, 2*sizeof(double), nrrdValCompare[nrrdTypeDouble]); wght = 0; for (nidx=0; nidx<fd*fd*fd; nidx++) { wght += iv3wght[1 + 2*nidx]; if (wght > wghtSum/2) { break; } } pvl->directAnswer[gageSclMedian][0] = iv3wght[0 + 2*nidx]; } return; }
int main(int argc, char *argv[]) { char *me, *err, *outS; hestOpt *hopt=NULL; airArray *mop; int sx, sy, xi, yi, samp, version, whole, right; float *tdata; double p[3], xyz[3], q[4], len, hackcp=0, maxca; double ca, cp, mD[9], mRF[9], mRI[9], mT[9], hack; Nrrd *nten; mop = airMopNew(); me = argv[0]; hestOptAdd(&hopt, "n", "# samples", airTypeInt, 1, 1, &samp, "4", "number of glyphs along each edge of triangle"); hestOptAdd(&hopt, "p", "x y z", airTypeDouble, 3, 3, p, NULL, "location in quaternion quotient space"); hestOptAdd(&hopt, "ca", "max ca", airTypeDouble, 1, 1, &maxca, "0.8", "maximum ca to use at bottom edge of triangle"); hestOptAdd(&hopt, "r", NULL, airTypeInt, 0, 0, &right, NULL, "sample a right-triangle-shaped region, instead of " "a roughly equilateral triangle. "); hestOptAdd(&hopt, "w", NULL, airTypeInt, 0, 0, &whole, NULL, "sample the whole triangle of constant trace, " "instead of just the " "sixth of it in which the eigenvalues have the " "traditional sorted order. "); hestOptAdd(&hopt, "hack", "hack", airTypeDouble, 1, 1, &hack, "0.04", "this is a hack"); hestOptAdd(&hopt, "v", "version", airTypeInt, 1, 1, &version, "1", "which version of the Westin metrics to use to parameterize " "triangle; \"1\" for ISMRM 97, \"2\" for MICCAI 99"); hestOptAdd(&hopt, "o", "nout", airTypeString, 1, 1, &outS, "-", "output file to save tensors into"); 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); nten = nrrdNew(); airMopAdd(mop, nten, (airMopper)nrrdNuke, airMopAlways); if (!( 1 == version || 2 == version )) { fprintf(stderr, "%s: version must be 1 or 2 (not %d)\n", me, version); airMopError(mop); return 1; } if (right) { sx = samp; sy = (int)(1.0*samp/sqrt(3.0)); } else { sx = 2*samp-1; sy = samp; } if (nrrdMaybeAlloc_va(nten, nrrdTypeFloat, 4, AIR_CAST(size_t, 7), AIR_CAST(size_t, sx), AIR_CAST(size_t, sy), AIR_CAST(size_t, 3))) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: couldn't allocate output:\n%s\n", me, err); airMopError(mop); return 1; } q[0] = 1.0; q[1] = p[0]; q[2] = p[1]; q[3] = p[2]; len = ELL_4V_LEN(q); ELL_4V_SCALE(q, 1.0/len, q); washQtoM3(mRF, q); ELL_3M_TRANSPOSE(mRI, mRF); if (right) { _ra2t(nten, 0.00, 0.0, mRI, mRF, hack); _ra2t(nten, 0.10, 0.0, mRI, mRF, hack); _ra2t(nten, 0.10, 60.0, mRI, mRF, hack); _ra2t(nten, 0.20, 0.0, mRI, mRF, hack); _ra2t(nten, 0.20, 30.0, mRI, mRF, hack); _ra2t(nten, 0.20, 60.0, mRI, mRF, hack); _ra2t(nten, 0.30, 0.0, mRI, mRF, hack); _ra2t(nten, 0.30, 20.0, mRI, mRF, hack); _ra2t(nten, 0.30, 40.0, mRI, mRF, hack); _ra2t(nten, 0.30, 60.0, mRI, mRF, hack); _ra2t(nten, 0.40, 0.0, mRI, mRF, hack); _ra2t(nten, 0.40, 15.0, mRI, mRF, hack); _ra2t(nten, 0.40, 30.0, mRI, mRF, hack); _ra2t(nten, 0.40, 45.0, mRI, mRF, hack); _ra2t(nten, 0.40, 60.0, mRI, mRF, hack); _ra2t(nten, 0.50, 0.0, mRI, mRF, hack); _ra2t(nten, 0.50, 12.0, mRI, mRF, hack); _ra2t(nten, 0.50, 24.0, mRI, mRF, hack); _ra2t(nten, 0.50, 36.0, mRI, mRF, hack); _ra2t(nten, 0.50, 48.0, mRI, mRF, hack); _ra2t(nten, 0.50, 60.0, mRI, mRF, hack); /* _ra2t(nten, 0.60, 30.0, mRI, mRF, hack); */ _ra2t(nten, 0.60, 40.0, mRI, mRF, hack); _ra2t(nten, 0.60, 50.0, mRI, mRF, hack); _ra2t(nten, 0.60, 60.0, mRI, mRF, hack); /* _ra2t(nten, 0.70, 34.3, mRI, mRF, hack); */ /* _ra2t(nten, 0.70, 42.8, mRI, mRF, hack); */ _ra2t(nten, 0.70, 51.4, mRI, mRF, hack); _ra2t(nten, 0.70, 60.0, mRI, mRF, hack); /* _ra2t(nten, 0.80, 45.0, mRI, mRF, hack); */ _ra2t(nten, 0.80, 52.5, mRI, mRF, hack); _ra2t(nten, 0.80, 60.0, mRI, mRF, hack); _ra2t(nten, 0.90, 60.0, mRI, mRF, hack); _ra2t(nten, 1.00, 60.0, mRI, mRF, hack); /* _ra2t(nten, 0.000, 0.0, mRI, mRF, hack); _ra2t(nten, 0.125, 0.0, mRI, mRF, hack); _ra2t(nten, 0.125, 60.0, mRI, mRF, hack); _ra2t(nten, 0.250, 0.0, mRI, mRF, hack); _ra2t(nten, 0.250, 30.0, mRI, mRF, hack); _ra2t(nten, 0.250, 60.0, mRI, mRF, hack); _ra2t(nten, 0.375, 0.0, mRI, mRF, hack); _ra2t(nten, 0.375, 20.0, mRI, mRF, hack); _ra2t(nten, 0.375, 40.0, mRI, mRF, hack); _ra2t(nten, 0.375, 60.0, mRI, mRF, hack); _ra2t(nten, 0.500, 0.0, mRI, mRF, hack); _ra2t(nten, 0.500, 15.0, mRI, mRF, hack); _ra2t(nten, 0.500, 30.0, mRI, mRF, hack); _ra2t(nten, 0.500, 45.0, mRI, mRF, hack); _ra2t(nten, 0.500, 60.0, mRI, mRF, hack); _ra2t(nten, 0.625, 37.0, mRI, mRF, hack); _ra2t(nten, 0.625, 47.5, mRI, mRF, hack); _ra2t(nten, 0.625, 60.0, mRI, mRF, hack); _ra2t(nten, 0.750, 49.2, mRI, mRF, hack); _ra2t(nten, 0.750, 60.0, mRI, mRF, hack); _ra2t(nten, 0.875, 60.0, mRI, mRF, hack); _ra2t(nten, 1.000, 60.0, mRI, mRF, hack); */ nten->axis[1].spacing = 1; nten->axis[2].spacing = (sx-1)/(sqrt(3.0)*(sy-1)); nten->axis[3].spacing = 1; } else { for (yi=0; yi<samp; yi++) { if (whole) { ca = AIR_AFFINE(0, yi, samp-1, 0.0, 1.0); } else { ca = AIR_AFFINE(0, yi, samp-1, hack, maxca); hackcp = AIR_AFFINE(0, yi, samp-1, hack, 0); } for (xi=0; xi<=yi; xi++) { if (whole) { cp = AIR_AFFINE(0, xi, samp-1, 0.0, 1.0); } else { cp = AIR_AFFINE(0, xi, samp-1, hackcp, maxca-hack/2.0); } _cap2xyz(xyz, ca, cp, version, whole); /* fprintf(stderr, "%s: (%d,%d) -> (%g,%g) -> %g %g %g\n", me, yi, xi, ca, cp, xyz[0], xyz[1], xyz[2]); */ ELL_3M_IDENTITY_SET(mD); ELL_3M_DIAG_SET(mD, xyz[0], xyz[1], xyz[2]); ELL_3M_IDENTITY_SET(mT); ell_3m_post_mul_d(mT, mRI); ell_3m_post_mul_d(mT, mD); ell_3m_post_mul_d(mT, mRF); tdata = (float*)nten->data + 7*(2*(samp-1-xi) - (samp-1-yi) + (2*samp-1)*((samp-1-yi) + samp)); tdata[0] = 1.0; TEN_M2T(tdata, mT); } } nten->axis[1].spacing = 1; nten->axis[2].spacing = 1.5; nten->axis[3].spacing = 1; } if (nrrdSave(outS, nten, NULL)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "%s: couldn't save output:\n%s\n", me, err); airMopError(mop); return 1; } airMopOkay(mop); return 0; }