/* ******** tenGradientJitter ** ** moves all gradients by amount dist on tangent plane, in a random ** direction, and then renormalizes. The distance is a fraction ** of the ideal edge length (via tenGradientIdealEdge) */ int tenGradientJitter(Nrrd *nout, const Nrrd *nin, double dist) { static const char me[]="tenGradientJitter"; double *grad, perp0[3], perp1[3], len, theta, cc, ss, edge; unsigned int gi, num; if (nrrdConvert(nout, nin, nrrdTypeDouble)) { biffMovef(TEN, NRRD, "%s: trouble converting input to double", me); return 1; } if (tenGradientCheck(nout, nrrdTypeDouble, 3)) { biffAddf(TEN, "%s: didn't get valid gradients", me); return 1; } grad = AIR_CAST(double*, nout->data); num = AIR_UINT(nout->axis[1].size); /* HEY: possible confusion between single and not */ edge = tenGradientIdealEdge(num, AIR_FALSE); for (gi=0; gi<num; gi++) { ELL_3V_NORM(grad, grad, len); ell_3v_perp_d(perp0, grad); ELL_3V_CROSS(perp1, perp0, grad); theta = AIR_AFFINE(0, airDrandMT(), 1, 0, 2*AIR_PI); cc = dist*edge*cos(theta); ss = dist*edge*sin(theta); ELL_3V_SCALE_ADD3(grad, 1.0, grad, cc, perp0, ss, perp1); ELL_3V_NORM(grad, grad, len); grad += 3; } return 0; }
void testeigen(double tt[7], double eval[3], double evec[9]) { double mat[9], dot[3], cross[3]; unsigned int ii; TEN_T2M(mat, tt); printf("evals %g %g %g\n", eval[0], eval[1], eval[2]); printf("evec0 (%g) %g %g %g\n", ELL_3V_LEN(evec + 0), evec[0], evec[1], evec[2]); printf("evec1 (%g) %g %g %g\n", ELL_3V_LEN(evec + 3), evec[3], evec[4], evec[5]); printf("evec2 (%g) %g %g %g\n", ELL_3V_LEN(evec + 6), evec[6], evec[7], evec[8]); printf("Mv - lv: (len) X Y Z (should be ~zeros)\n"); for (ii=0; ii<3; ii++) { double uu[3], vv[3], dd[3]; ELL_3MV_MUL(uu, mat, evec + 3*ii); ELL_3V_SCALE(vv, eval[ii], evec + 3*ii); ELL_3V_SUB(dd, uu, vv); printf("%d: (%g) %g %g %g\n", ii, ELL_3V_LEN(dd), dd[0], dd[1], dd[2]); } dot[0] = ELL_3V_DOT(evec + 0, evec + 3); dot[1] = ELL_3V_DOT(evec + 0, evec + 6); dot[2] = ELL_3V_DOT(evec + 3, evec + 6); printf("pairwise dots: (%g) %g %g %g\n", ELL_3V_LEN(dot), dot[0], dot[1], dot[2]); ELL_3V_CROSS(cross, evec+0, evec+3); printf("right-handed: %g\n", ELL_3V_DOT(evec+6, cross)); return; }
/* ** makes sure that v+3*2 has a positive dot product with ** cross product of v+3*0 and v+3*1 */ void _ell_3m_make_right_handed_d(double v[9]) { double x[3]; ELL_3V_CROSS(x, v+3*0, v+3*1); if (0 > ELL_3V_DOT(x, v+3*2)) { ELL_3V_SCALE(v+3*2, -1, v+3*2); } }
/* ******** ell_3m_1d_nullspace_d() ** ** the given matrix is assumed to have a nullspace of dimension one. ** A normalized vector which spans the nullspace is put into ans. ** ** The given nullspace matrix is NOT modified. ** ** This does NOT use biff */ void ell_3m_1d_nullspace_d(double ans[3], const double _n[9]) { double t[9], n[9], norm; ELL_3M_TRANSPOSE(n, _n); /* find the three cross-products of pairs of column vectors of n */ ELL_3V_CROSS(t+0, n+0, n+3); ELL_3V_CROSS(t+3, n+0, n+6); ELL_3V_CROSS(t+6, n+3, n+6); /* lop A */ _ell_align3_d(t); /* lop B */ /* add them up (longer, hence more accurate, should dominate) */ ELL_3V_ADD3(ans, t+0, t+3, t+6); /* normalize */ ELL_3V_NORM(ans, ans, norm); return; }
/* Estimates the shortest distance from a point to a line going through the origin */ double _tenPldist( const double point[], const double line[] ) { double cross[3]; double negpoint[3]; negpoint[0] = -point[0]; negpoint[1] = -point[1]; negpoint[2] = -point[2]; ELL_3V_CROSS( cross, line, negpoint ); return ELL_3V_LEN( cross ) / ELL_3V_LEN( line ); }
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; }
/* ******** ell_3m_2d_nullspace_d() ** ** the given matrix is assumed to have a nullspace of dimension two. ** ** The given nullspace matrix is NOT modified ** ** This does NOT use biff */ void ell_3m_2d_nullspace_d(double ans0[3], double ans1[3], const double _n[9]) { double n[9], tmp[3], norm; ELL_3M_TRANSPOSE(n, _n); _ell_align3_d(n); ELL_3V_ADD3(tmp, n+0, n+3, n+6); ELL_3V_NORM(tmp, tmp, norm); /* any two vectors which are perpendicular to the (supposedly 1D) span of the column vectors span the nullspace */ ell_3v_perp_d(ans0, tmp); ELL_3V_NORM(ans0, ans0, norm); ELL_3V_CROSS(ans1, tmp, ans0); return; }
/* ** NOTE: assumes that eval and roots have come from ** ell_3m2sub_eigenvalues_d(m) */ void _ell_3m2sub_evecs_d(double evec[9], double eval[3], int roots, const double m[9]) { double n[4]; static const char me[]="_ell_3m2sub_evecs_d"; if (ell_cubic_root_three == roots) { /* set off-diagonal entries once */ n[1] = m[1]; n[2] = m[3]; /* find first evec */ n[0] = m[0] - eval[0]; n[3] = m[3] - eval[0]; ell_2m_1d_nullspace_d(evec + 3*0, n); (evec + 3*0)[2] = 0; /* find second evec */ n[0] = m[0] - eval[1]; n[3] = m[3] - eval[1]; ell_2m_1d_nullspace_d(evec + 3*1, n); (evec + 3*1)[2] = 0; _ell_22v_enforce_orthogonality(evec + 3*0, evec + 3*1); /* make right-handed */ ELL_3V_CROSS(evec + 3*2, evec + 3*0, evec + 3*1); } else if (ell_cubic_root_single_double == roots) { /* can pick any 2D basis */ ELL_3V_SET(evec + 3*0, 1, 0, 0); ELL_3V_SET(evec + 3*1, 0, 1, 0); ELL_3V_SET(evec + 3*2, 0, 0, 1); } else { /* ell_cubic_root_single == roots, if assumptions are met */ ELL_3V_SET(evec + 3*0, AIR_NAN, AIR_NAN, 0); ELL_3V_SET(evec + 3*1, AIR_NAN, AIR_NAN, 0); ELL_3V_SET(evec + 3*2, 0, 0, 1); } if (!ELL_3M_EXISTS(evec)) { fprintf(stderr, "%s: given m = \n", me); ell_3m_print_d(stderr, m); fprintf(stderr, "%s: got roots = %s (%d) and evecs = \n", me, airEnumStr(ell_cubic_root, roots), roots); ell_3m_print_d(stderr, evec); } return; }
int _echoRayIntx_Triangle(RAYINTX_ARGS(Triangle)) { echoPos_t pvec[3], qvec[3], tvec[3], det, t, u, v, edge0[3], edge1[3], tmp; AIR_UNUSED(parm); AIR_UNUSED(tstate); ELL_3V_SUB(edge0, obj->vert[1], obj->vert[0]); ELL_3V_SUB(edge1, obj->vert[2], obj->vert[0]); TRI_INTX(ray, obj->vert[0], edge0, edge1, pvec, qvec, tvec, det, t, u, v, (v < 0.0 || u + v > 1.0), return AIR_FALSE); intx->t = t; intx->u = u; intx->v = v; ELL_3V_CROSS(intx->norm, edge0, edge1); ELL_3V_NORM(intx->norm, intx->norm, tmp); intx->obj = (echoObject *)obj; /* DOES set u, v */ return AIR_TRUE; }
int _echoRayIntx_Rectangle(RAYINTX_ARGS(Rectangle)) { echoPos_t pvec[3], qvec[3], tvec[3], det, t, u, v, *edge0, *edge1, tmp; AIR_UNUSED(tstate); if (echoMatterLight == obj->matter && (ray->shadow || !parm->renderLights)) { return AIR_FALSE; } edge0 = obj->edge0; edge1 = obj->edge1; TRI_INTX(ray, obj->origin, edge0, edge1, pvec, qvec, tvec, det, t, u, v, (v < 0.0 || v > 1.0), return AIR_FALSE); intx->t = t; intx->u = u; intx->v = v; ELL_3V_CROSS(intx->norm, edge0, edge1); ELL_3V_NORM(intx->norm, intx->norm, tmp); intx->obj = OBJECT(obj); /* DOES set u, v */ return AIR_TRUE; }
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 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; }
/* ** parm vector: ** 0 1 2 3 4 5 (6) ** step K_perp K_tan lerp X_ring Y_ring */ void _coilKindScalarFilterModifiedCurvatureRings(coil_t *delta, int xi, int yi, int zi, coil_t **iv3, double spacing[3], double parm[COIL_PARMS_NUM]) { coil_t forwX[3], backX[3], forwY[3], backY[3], forwZ[3], backZ[3], grad[3], gm, eps, KK, LL, denom, rspX, rspY, rspZ, lerp; double bas0[3], bas1[3], bas2[3], len, norm[3], sk; AIR_UNUSED(zi); ELL_3V_SET(bas0, 0, 0, 1); ELL_3V_SET(bas1, xi - parm[4], yi - parm[5], 0); ELL_3V_NORM(bas1, bas1, len); ELL_3V_CROSS(bas2, bas0, bas1); rspX = AIR_CAST(coil_t, 1.0/spacing[0]); rspY = AIR_CAST(coil_t, 1.0/spacing[1]); rspZ = AIR_CAST(coil_t, 1.0/spacing[2]); _coilKindScalar3x3x3Gradients(forwX, backX, forwY, backY, forwZ, backZ, iv3, rspX, rspY, rspZ); grad[0] = rspX*(iv3[2][4] - iv3[0][4]); grad[1] = rspY*(iv3[1][5] - iv3[1][3]); grad[2] = rspZ*(iv3[1][7] - iv3[1][1]); gm = AIR_CAST(coil_t, ELL_3V_LEN(grad)); if (gm) { double tc, rcsq; ELL_3V_SCALE(norm, 1.0/gm, grad); tc = ELL_3V_DOT(norm, bas2); rcsq = 1 - tc*tc; sk = AIR_LERP(rcsq, parm[1], parm[2]); } else { sk = parm[1]; } /* compute fluxes */ eps = 0.0000000001f; KK = AIR_CAST(coil_t, sk*sk); LL = ELL_3V_DOT(forwX, forwX); denom = AIR_CAST(coil_t, 1.0/(eps + sqrt(LL))); forwX[0] *= _COIL_CONDUCT(LL, KK)*denom; LL = ELL_3V_DOT(forwY, forwY); denom = AIR_CAST(coil_t, 1.0/(eps + sqrt(LL))); forwY[1] *= _COIL_CONDUCT(LL, KK)*denom; LL = ELL_3V_DOT(forwZ, forwZ); denom = AIR_CAST(coil_t, 1.0/(eps + sqrt(LL))); forwZ[2] *= _COIL_CONDUCT(LL, KK)*denom; LL = ELL_3V_DOT(backX, backX); denom = AIR_CAST(coil_t, 1.0/(eps + sqrt(LL))); backX[0] *= _COIL_CONDUCT(LL, KK)*denom; LL = ELL_3V_DOT(backY, backY); denom = AIR_CAST(coil_t, 1.0/(eps + sqrt(LL))); backY[1] *= _COIL_CONDUCT(LL, KK)*denom; LL = ELL_3V_DOT(backZ, backZ); denom = AIR_CAST(coil_t, 1.0/(eps + sqrt(LL))); backZ[2] *= _COIL_CONDUCT(LL, KK)*denom; lerp = AIR_CAST(coil_t, parm[2]); delta[0] = (lerp*_coilLaplacian3(iv3, spacing) + (1-lerp)*gm*(rspX*(forwX[0] - backX[0]) + rspY*(forwY[1] - backY[1]) + rspZ*(forwZ[2] - backZ[2]))); delta[0] *= AIR_CAST(coil_t, parm[0]); }
/* ** Thanks to: ** http://jgt.akpeters.com/papers/MollerHughes99/code.html */ void ell_3m_rotate_between_d(double rot[9], double from[3], double to[3]) { double vv[3]; double e, h, f; if (!( rot && from && to)) { return; } ELL_3V_CROSS(vv, from, to); e = ELL_3V_DOT(from, to); f = AIR_ABS(e); if (f > 0.9999999) { /* "from" and "to"-vector almost parallel */ double tu[3], tv[3]; /* temporary storage vectors */ double xx[3]; /* vector most nearly orthogonal to "from" */ double c1, c2, c3; /* coefficients for later use */ int i, j; xx[0] = AIR_ABS(from[0]); xx[1] = AIR_ABS(from[1]); xx[2] = AIR_ABS(from[2]); if (xx[0] < xx[1]) { if (xx[0] < xx[2]) { xx[0] = 1.0; xx[1] = xx[2] = 0.0; } else { xx[2] = 1.0; xx[0] = xx[1] = 0.0; } } else { if (xx[1] < xx[2]) { xx[1] = 1.0; xx[0] = xx[2] = 0.0; } else { xx[2] = 1.0; xx[0] = xx[1] = 0.0; } } tu[0] = xx[0] - from[0]; tu[1] = xx[1] - from[1]; tu[2] = xx[2] - from[2]; tv[0] = xx[0] - to[0]; tv[1] = xx[1] - to[1]; tv[2] = xx[2] - to[2]; c1 = 2.0 / ELL_3V_DOT(tu, tu); c2 = 2.0 / ELL_3V_DOT(tv, tv); c3 = c1 * c2 * ELL_3V_DOT(tu, tv); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { rot[3*i + j] = - c1 * tu[i] * tu[j] - c2 * tv[i] * tv[j] + c3 * tv[i] * tu[j]; } rot[3*i + i] += 1.0; } } else { /* the most common case, unless "from"="to", or "from"=-"to" */ double hvx, hvz, hvxy, hvxz, hvyz; h = 1.0/(1.0 + e); /* optimization by Gottfried Chen */ hvx = h * vv[0]; hvz = h * vv[2]; hvxy = hvx * vv[1]; hvxz = hvx * vv[2]; hvyz = hvz * vv[1]; rot[3*0 + 0] = e + hvx * vv[0]; rot[3*0 + 1] = hvxy - vv[2]; rot[3*0 + 2] = hvxz + vv[1]; rot[3*1 + 0] = hvxy + vv[2]; rot[3*1 + 1] = e + h * vv[1] * vv[1]; rot[3*1 + 2] = hvyz - vv[0]; rot[3*2 + 0] = hvxz - vv[1]; rot[3*2 + 1] = hvyz + vv[0]; rot[3*2 + 2] = e + hvz * vv[2]; } return; }
/* ******** limnCameraUpdate() ** ** sets in cam: W2V, V2W, U, V, N, vspNeer, vspFaar, vspDist ** and, if fov and aspect are set, this also sets uRange and vRange ** ** This does use biff to describe problems with camera settings */ int limnCameraUpdate(limnCamera *cam) { static const char me[] = "limnCameraUpdate"; double len, bb[4], uu[4], vv[4], nn[4], TT[16], RR[16]; if (!cam) { biffAddf(LIMN, "%s: got NULL pointer", me); return 1; } ELL_4V_SET(uu, 0, 0, 0, 0); ELL_4V_SET(vv, 0, 0, 0, 0); ELL_4V_SET(nn, 0, 0, 0, 0); ELL_4V_SET(bb, 0, 0, 0, 1); ELL_3V_SUB(nn, cam->at, cam->from); len = ELL_3V_LEN(nn); if (!len) { biffAddf(LIMN, "%s: cam->at (%g,%g,%g) == cam->from", me, cam->at[0], cam->at[1], cam->at[2]); return 1; } if (cam->atRelative) { /* ctx->cam->{neer,dist} are "at" relative */ cam->vspNeer = cam->neer + len; cam->vspFaar = cam->faar + len; cam->vspDist = cam->dist + len; } else { /* ctx->cam->{neer,dist} are eye relative */ cam->vspNeer = cam->neer; cam->vspFaar = cam->faar; cam->vspDist = cam->dist; } if (!(cam->vspNeer > 0 && cam->vspDist > 0 && cam->vspFaar > 0)) { biffAddf(LIMN, "%s: eye-relative near (%g), dist (%g), or far (%g) <= 0", me, cam->vspNeer, cam->vspDist, cam->vspFaar); return 1; } if (!(cam->vspNeer <= cam->vspFaar)) { biffAddf(LIMN, "%s: eye-relative near (%g) further than far (%g)", me, cam->vspNeer, cam->vspFaar); return 1 ; } if (AIR_EXISTS(cam->fov)) { if (!( AIR_IN_OP(0.0, cam->fov, 180.0) )) { biffAddf(LIMN, "%s: cam->fov (%g) not in valid range between 0 and 180", me, cam->fov); return 1 ; } if (!AIR_EXISTS(cam->aspect)) { biffAddf(LIMN, "%s: cam->fov set, but cam->aspect isn't", me); return 1; } /* "fov" is half vertical angle */ cam->vRange[0] = -tan(cam->fov*AIR_PI/360)*(cam->vspDist); cam->vRange[1] = -cam->vRange[0]; cam->uRange[0] = cam->vRange[0]*(cam->aspect); cam->uRange[1] = -cam->uRange[0]; } /* else cam->fov isn't set, but we're not going to complain if uRange and vRange aren't both set ... */ ELL_3V_SCALE(nn, 1.0/len, nn); ELL_3V_CROSS(uu, nn, cam->up); len = ELL_3V_LEN(uu); if (!len) { biffAddf(LIMN, "%s: cam->up is co-linear with view direction", me); return 1 ; } ELL_3V_SCALE(uu, 1.0/len, uu); if (cam->rightHanded) { ELL_3V_CROSS(vv, nn, uu); } else { ELL_3V_CROSS(vv, uu, nn); } ELL_4V_COPY(cam->U, uu); ELL_4V_COPY(cam->V, vv); ELL_4V_COPY(cam->N, nn); ELL_4M_TRANSLATE_SET(TT, -cam->from[0], -cam->from[1], -cam->from[2]); ELL_4M_ROWS_SET(RR, uu, vv, nn, bb); ELL_4M_MUL(cam->W2V, RR, TT); ell_4m_inv_d(cam->V2W, cam->W2V); return 0; }
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; }