/* XX != AB */ static int lattXXtoAB(double *dstParm, int srcLatt, const double *srcParm) { double AA[2], BB[2], area, theta, radi, scl; int ret = 0; switch(srcLatt) { case rvaLattPRA: /* PRA -> AB */ area = AIR_ABS(srcParm[2]); theta = AIR_AFFINE(0, srcParm[0], 1, AIR_PI/2, AIR_PI/3); radi = srcParm[1]; ELL_2V_SET(AA, 1.0, 0.0); ELL_2V_SET(BB, radi*cos(theta), radi*sin(theta)); /* area from AA and BB is BB[1], but need to scale these to get to requested area */ scl = sqrt(area/BB[1]); ELL_4V_SET(dstParm, scl*AA[0], scl*AA[1], scl*BB[0], scl*BB[1]); break; case rvaLattAB: /* UVW -> AB */ ELL_4V_SET(dstParm, srcParm[2], 0.0, srcParm[0], srcParm[1]); break; case rvaLattXY: /* XY -> AB */ ELL_4V_SET(dstParm, 1.0, 0.0, srcParm[0], srcParm[1]); break; default: ret = 1; break; /* unimplemented */ } return ret; }
/* ** its in here that we scale from "energy gradient" to "force" */ double _pullPointEnergyTotal(pullTask *task, pullBin *bin, pullPoint *point, /* output */ double force[4]) { char me[]="_pullPointEnergyTotal"; double enrIm, enrPt, egradIm[4], egradPt[4], energy; ELL_4V_SET(egradIm, 0, 0, 0, 0); /* sssh */ ELL_4V_SET(egradPt, 0, 0, 0, 0); /* sssh */ enrIm = _energyFromImage(task, point, force ? egradIm : NULL); enrPt = _energyFromPoints(task, bin, point, force ? egradPt : NULL); energy = AIR_LERP(task->pctx->alpha, enrIm, enrPt); /* fprintf(stderr, "!%s(%u): energy = lerp(%g, im %g, pt %g) = %g\n", me, point->idtag, task->pctx->alpha, enrIm, enrPt, energy); */ if (force) { ELL_4V_LERP(force, task->pctx->alpha, egradIm, egradPt); ELL_4V_SCALE(force, -1, force); /* fprintf(stderr, "!%s(%u): egradIm = %g %g %g %g\n", me, point->idtag, egradIm[0], egradIm[1], egradIm[2], egradIm[3]); fprintf(stderr, "!%s(%u): egradPt = %g %g %g %g\n", me, point->idtag, egradPt[0], egradPt[1], egradPt[2], egradPt[3]); fprintf(stderr, "!%s(%u): ---> force = %g %g %g %g\n", me, point->idtag, force[0], force[1], force[2], force[3]); */ } if (task->pctx->wall) { unsigned int axi; double frc; for (axi=0; axi<4; axi++) { frc = task->pctx->bboxMin[axi] - point->pos[axi]; if (frc < 0) { /* not below min */ frc = task->pctx->bboxMax[axi] - point->pos[axi]; if (frc > 0) { /* not above max */ frc = 0; } } energy += task->pctx->wall*frc*frc/2; if (force) { force[axi] += task->pctx->wall*frc; } } } if (!AIR_EXISTS(energy)) { fprintf(stderr, "!%s(%u): HEY! non-exist energy %g\n", me, point->idtag, energy); } return energy; }
/* ******** limnLightSet() ** ** turns on a light ** */ void limnLightSet(limnLight *lit, int which, int vsp, float r, float g, float b, float x, float y, float z) { if (lit && AIR_IN_CL(0, which, LIMN_LIGHT_NUM-1)) { lit->on[which] = 1; lit->vsp[which] = vsp; ELL_4V_SET(lit->col[which], r, g, b, 1.0); ELL_4V_SET(lit->_dir[which], x, y, z, 0.0); } }
void limnLightReset(limnLight *lit) { int i; if (lit) { ELL_4V_SET(lit->amb, 0, 0, 0, 1); for (i=0; i<LIMN_LIGHT_NUM; i++) { ELL_4V_SET(lit->_dir[i], 0, 0, 0, 0); ELL_4V_SET(lit->dir[i], 0, 0, 0, 0); ELL_4V_SET(lit->col[i], 0, 0, 0, 1); lit->on[i] = AIR_FALSE; lit->vsp[i] = AIR_FALSE; } } }
/* ******** limnLightAmbientSet() ** ** sets the ambient light color */ void limnLightAmbientSet(limnLight *lit, float r, float g, float b) { if (lit) { ELL_4V_SET(lit->amb, r, g, b, 1.0); } }
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; }
double _energyFromImage(pullTask *task, pullPoint *point, /* output */ double egradSum[4]) { char me[]="_energyFromImage"; double energy, grad3[3]; int probed; /* not sure I have the logic for this right int ptrue; if (task->pctx->probeProb < 1 && allowProbeProb) { if (egrad) { ptrue = (0 == task->pctx->iter || airDrandMT_r(task->rng) < task->pctx->probeProb); } else { ptrue = AIR_FALSE; } } else { ptrue = AIR_TRUE; } */ probed = AIR_FALSE; #define MAYBEPROBE \ if (!probed) { \ if (_pullProbe(task, point)) { \ fprintf(stderr, "%s: problem probing!!!\n%s\n", me, biffGetDone(PULL)); \ } \ probed = AIR_TRUE; \ } energy = 0; if (egradSum) { ELL_4V_SET(egradSum, 0, 0, 0, 0); } if (task->pctx->ispec[pullInfoHeight] && !task->pctx->ispec[pullInfoHeight]->constraint && (!task->pctx->ispec[pullInfoHeightLaplacian] || !task->pctx->ispec[pullInfoHeightLaplacian]->constraint)) { MAYBEPROBE; energy += _pullPointScalar(task->pctx, point, pullInfoHeight, grad3, NULL); if (egradSum) { ELL_3V_INCR(egradSum, grad3); } } if (task->pctx->ispec[pullInfoIsovalue] && !task->pctx->ispec[pullInfoIsovalue]->constraint) { /* we're only going towards an isosurface, not constrained to it ==> set up a parabolic potential well around the isosurface */ double val; MAYBEPROBE; val = _pullPointScalar(task->pctx, point, pullInfoIsovalue, grad3, NULL); energy += val*val; if (egradSum) { ELL_3V_SCALE_INCR(egradSum, 2*val, grad3); } } return energy; }
void ell_q_log_f(float q2[4], const float q1[4]) { float a, b, axis[3]; a = AIR_CAST(float, log(ELL_4V_LEN(q1))); b = ell_q_to_aa_f(axis, q1)/2.0f; ELL_4V_SET(q2, a, b*axis[0], b*axis[1], b*axis[2]); }
void ell_q_log_d(double q2[4], const double q1[4]) { double a, b, axis[3]; a = log(ELL_4V_LEN(q1)); b = ell_q_to_aa_d(axis, q1)/2.0; ELL_4V_SET(q2, a, b*axis[0], b*axis[1], b*axis[2]); }
void echoColorSet(echoObject *obj, echoCol_t R, echoCol_t G, echoCol_t B, echoCol_t A) { if (obj && echoObjectHasMatter[obj->type]) { ELL_4V_SET(obj->rgba, R, G, B, A); } }
void _echoMatterInit(echoObject *obj) { obj->matter = echoMatterUnknown; ELL_4V_SET(obj->rgba, 0, 0, 0, 0); memset(obj->mat, 0,ECHO_MATTER_PARM_NUM*sizeof(echoCol_t)); obj->ntext = NULL; }
int soidDoit(limnObject *obj, int look, int gtype, float gamma, int res, float AB[2], float ten[7]) { int partIdx, axis; float cl, cp, qA, qB, eval[3], evec[9], matA[16], matB[16]; if (AB) { qA = AB[0]; qB = AB[1]; axis = 2; } else { tenEigensolve_f(eval, evec, ten); 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 = 0; qA = pow(1-cp, gamma); qB = pow(1-cl, gamma); } else { axis = 2; qA = pow(1-cl, gamma); qB = pow(1-cp, gamma); } /* 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 (tenGlyphTypeBox == gtype) { partIdx = limnObjectCubeAdd(obj, look); } else if (tenGlyphTypeSphere == gtype) { partIdx = limnObjectPolarSphereAdd(obj, look, 0, 2*res, res); } else { partIdx = limnObjectPolarSuperquadAdd(obj, look, axis, qA, qB, 2*res, res); } ELL_4M_IDENTITY_SET(matA); ELL_4V_SET(matB + 0*4, eval[0], 0, 0, 0); ELL_4V_SET(matB + 1*4, 0, eval[1], 0, 0); ELL_4V_SET(matB + 2*4, 0, 0, eval[2], 0); ELL_4V_SET(matB + 3*4, 0, 0, 0, 1); ELL_4M_SCALE_SET(matB, eval[0], eval[1], eval[2]); ell_4m_post_mul_f(matA, matB); ELL_4V_SET(matB + 0*4, evec[0 + 0*3], evec[0 + 1*3], evec[0 + 2*3], 0); ELL_4V_SET(matB + 1*4, evec[1 + 0*3], evec[1 + 1*3], evec[1 + 2*3], 0); ELL_4V_SET(matB + 2*4, evec[2 + 0*3], evec[2 + 1*3], evec[2 + 2*3], 0); ELL_4V_SET(matB + 3*4, 0, 0, 0, 1); ell_4m_post_mul_f(matA, matB); limnObjectPartTransform(obj, partIdx, matA); return partIdx; }
void _limnSplineWeightsFind_Linear(double *wght, limnSpline *spline, double f) { AIR_UNUSED(spline); ELL_4V_SET(wght, 0, 1-f, f, 0); /* fprintf(stderr, "%g ----> %g %g %g %g\n", f, wght[0], wght[1], wght[2], wght[3]); */ return; }
double _energyInterParticle(pullTask *task, pullPoint *me, pullPoint *she, /* output */ double egrad[4]) { char meme[]="_energyInterParticle"; double spadist, sparad, diff[4], rr, enr, frc, *parm; ELL_4V_SUB(diff, she->pos, me->pos); spadist = ELL_3V_LEN(diff); sparad = task->pctx->radiusSpace; rr = spadist/(2*sparad); /* fprintf(stderr, "!%s: rr(%u,%u) = %g\n", meme, me->idtag, she->idtag, rr); */ if (rr > 1) { ELL_4V_SET(egrad, 0, 0, 0, 0); return 0; } if (rr == 0) { fprintf(stderr, "%s: pos of pts %u, %u equal: (%g,%g,%g,%g)\n", meme, me->idtag, she->idtag, me->pos[0], me->pos[1], me->pos[2], me->pos[3]); ELL_4V_SET(egrad, 0, 0, 0, 0); return 0; } parm = task->pctx->energySpec->parm; enr = task->pctx->energySpec->energy->eval(&frc, rr, parm); frc *= -1.0/(2*sparad*spadist); ELL_3V_SCALE(egrad, frc, diff); egrad[3] = 0; /* fprintf(stderr, "%s: %u <-- %u = %g,%g,%g -> egrad = %g,%g,%g, enr = %g\n", meme, me->idtag, she->idtag, diff[0], diff[1], diff[2], egrad[0], egrad[1], egrad[2], enr); */ return enr; }
void _limnSplineWeightsFind_Hermite(double *wght, limnSpline *spline, double f) { double f3, f2; AIR_UNUSED(spline); f3 = f*(f2 = f*f); ELL_4V_SET(wght, 2*f3 - 3*f2 + 1, f3 - 2*f2 + f, f3 - f2, -2*f3 + 3*f2); return; }
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 _limnSplineWeightsFind_CubicBezier(double *wght, limnSpline *spline, double f) { double g; AIR_UNUSED(spline); g = 1 - f; ELL_4V_SET(wght, g*g*g, 3*g*g*f, 3*g*f*f, f*f*f); return; }
void _limnSplineWeightsFind_BC(double *wght, limnSpline *spline, double f) { double B, C, f0, f1, f2, f3; B = spline->B; C = spline->C; f0 = f+1; f1 = f; f2 = AIR_ABS(f-1); f3 = AIR_ABS(f-2); ELL_4V_SET(wght, _BCCUBIC(f0, B, C), _BCCUBIC(f1, B, C), _BCCUBIC(f2, B, C), _BCCUBIC(f3, B, C)); return; }
tenGlyphParm * tenGlyphParmNew() { tenGlyphParm *parm; parm = (tenGlyphParm *)calloc(1, sizeof(tenGlyphParm)); if (parm) { parm->verbose = 0; parm->nmask = NULL; parm->anisoType = tenAnisoUnknown; parm->onlyPositive = AIR_TRUE; parm->confThresh = AIR_NAN; parm->anisoThresh = AIR_NAN; parm->maskThresh = AIR_NAN; parm->glyphType = tenGlyphTypeUnknown; parm->facetRes = 10; parm->glyphScale = 1.0; parm->sqdSharp = 3.0; ELL_5V_SET(parm->edgeWidth, 0.0f, 0.0f, 0.4f, 0.2f, 0.1f); parm->colEvec = 0; /* first */ parm->colMaxSat = 1; parm->colGamma = 1; parm->colIsoGray = 1; parm->colAnisoType = tenAnisoUnknown; parm->colAnisoModulate = 0; ELL_4V_SET(parm->ADSP, 0, 1, 0, 30); parm->doSlice = AIR_FALSE; parm->sliceAxis = 0; parm->slicePos = 0; parm->sliceAnisoType = tenAnisoUnknown; parm->sliceOffset = 0.0; parm->sliceBias = 0.05f; parm->sliceGamma = 1.0; } return parm; }
void _limnSplineIndexFind(int *idx, limnSpline *spline, int ii) { int N, ti[4]; N = spline->ncpt->axis[2].size; if (limnSplineTypeHasImplicitTangents[spline->type]) { if (spline->loop) { ELL_4V_SET(ti, AIR_MOD(ii-1, N), AIR_MOD(ii+0, N), AIR_MOD(ii+1, N), AIR_MOD(ii+2, N)); } else { ELL_4V_SET(ti, AIR_CLAMP(0, ii-1, N-1), AIR_CLAMP(0, ii+0, N-1), AIR_CLAMP(0, ii+1, N-1), AIR_CLAMP(0, ii+2, N-1)); } ELL_4V_SET(idx, 1 + 3*ti[0], 1 + 3*ti[1], 1 + 3*ti[2], 1 + 3*ti[3]); } else { if (spline->loop) { ELL_4V_SET(ti, AIR_MOD(ii+0, N), AIR_MOD(ii+0, N), AIR_MOD(ii+1, N), AIR_MOD(ii+1, N)); } else { ELL_4V_SET(ti, AIR_CLAMP(0, ii+0, N-1), AIR_CLAMP(0, ii+0, N-1), AIR_CLAMP(0, ii+1, N-1), AIR_CLAMP(0, ii+1, N-1)); } ELL_4V_SET(idx, 1 + 3*ti[0], 2 + 3*ti[1], 0 + 3*ti[2], 1 + 3*ti[3]); } }
int main(int argc, const char *argv[]) { const char *me; char *err, *outS; double scale[3], matA[9], matB[9], matC[9], sval[3], uu[9], vv[9]; float matAf[9], matBf[16]; float p[3], q[4], mR[9], len, gamma; float os, vs, rad, AB[2], ten[7], view[3]; hestOpt *hopt=NULL; airArray *mop; limnObject *obj; limnLook *look; int lookRod, lookSoid; int partIdx=-1; /* sssh */ int res, sphere; FILE *file; me = argv[0]; hestOptAdd(&hopt, "sc", "scalings", airTypeDouble, 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, "vs", "over-all scaling", airTypeFloat, 1, 1, &vs, "1", "scaling along view-direction (to show off bas-relief " "ambibuity of ellipsoids versus superquads)"); hestOptAdd(&hopt, "fr", "from (eye) point", airTypeFloat, 3, 3, &view, "4 4 4", "eye point, needed for non-unity \"-vs\""); hestOptAdd(&hopt, "gamma", "superquad sharpness", airTypeFloat, 1, 1, &gamma, "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(1000, AIR_TRUE); 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_3M_IDENTITY_SET(matA); ELL_3V_SCALE(scale, os, scale); ELL_3M_SCALE_SET(matB, scale[0], scale[1], scale[2]); ell_3m_post_mul_d(matA, matB); if (1 != vs) { ELL_3V_NORM(view, view, len); if (!len) { /* HEY: perhaps do more diplomatic error message here */ fprintf(stderr, "%s: stupido!\n", me); exit(1); } ELL_3MV_OUTER(matB, view, view); ELL_3M_SCALE(matB, vs-1, matB); ELL_3M_IDENTITY_SET(matC); ELL_3M_ADD2(matB, matC, matB); ell_3m_post_mul_d(matA, matB); } ell_3m_svd_d(uu, sval, vv, matA, AIR_TRUE); /* fprintf(stderr, "%s: ____________________________________\n", me); fprintf(stderr, "%s: mat = \n", me); ell_3m_print_d(stderr, matA); fprintf(stderr, "%s: uu = \n", me); ell_3m_print_d(stderr, uu); ELL_3M_TRANSPOSE(matC, uu); ELL_3M_MUL(matB, uu, matC); fprintf(stderr, "%s: uu * uu^T = \n", me); ell_3m_print_d(stderr, matB); fprintf(stderr, "%s: sval = %g %g %g\n", me, sval[0], sval[1], sval[2]); fprintf(stderr, "%s: vv = \n", me); ell_3m_print_d(stderr, vv); ELL_3M_MUL(matB, vv, vv); fprintf(stderr, "%s: vv * vv^T = \n", me); ELL_3M_TRANSPOSE(matC, vv); ELL_3M_MUL(matB, vv, matC); ell_3m_print_d(stderr, matB); ELL_3M_IDENTITY_SET(matA); ell_3m_pre_mul_d(matA, uu); ELL_3M_SCALE_SET(matB, sval[0], sval[1], sval[2]); ell_3m_pre_mul_d(matA, matB); ell_3m_pre_mul_d(matA, vv); fprintf(stderr, "%s: uu * diag(sval) * vv = \n", me); ell_3m_print_d(stderr, matA); fprintf(stderr, "%s: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", me); */ ELL_3M_IDENTITY_SET(matA); ell_3m_pre_mul_d(matA, uu); ELL_3M_SCALE_SET(matB, sval[0], sval[1], sval[2]); ell_3m_pre_mul_d(matA, matB); ELL_3M_TRANSPOSE(matB, uu); ell_3m_pre_mul_d(matA, matB); TEN_M2T(ten, matA); partIdx = soidDoit(obj, lookSoid, sphere, gamma, res, (AIR_EXISTS(AB[0]) && AIR_EXISTS(AB[1])) ? AB : NULL, ten); ELL_4V_SET(q, 1, p[0], p[1], p[2]); ELL_4V_NORM(q, q, len); ell_q_to_3m_f(mR, q); ELL_43M_INSET(matBf, mR); limnObjectPartTransform(obj, partIdx, matBf); if (rad) { partIdx = limnObjectCylinderAdd(obj, lookRod, 0, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, (1-scale[0])/2, rad, rad); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, (1+scale[0])/2, 0.0, 0.0); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); partIdx = limnObjectCylinderAdd(obj, lookRod, 0, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, (1-scale[0])/2, rad, rad); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, -(1+scale[0])/2, 0.0, 0.0); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); partIdx = limnObjectCylinderAdd(obj, lookRod, 1, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, rad, (1-scale[1])/2, rad); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, 0.0, (1+scale[1])/2, 0.0); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); partIdx = limnObjectCylinderAdd(obj, lookRod, 1, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, rad, (1-scale[1])/2, rad); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, 0.0, -(1+scale[1])/2, 0.0); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); partIdx = limnObjectCylinderAdd(obj, lookRod, 2, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, rad, rad, (1-scale[2])/2); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, 0.0, 0.0, (1+scale[2])/2); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); partIdx = limnObjectCylinderAdd(obj, lookRod, 2, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, rad, rad, (1-scale[2])/2); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, 0.0, 0.0, -(1+scale[2])/2); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); } 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; }
int limnPolyDataCube(limnPolyData *pld, unsigned int infoBitFlag, int sharpEdge) { char me[]="limnPolyDataCube", err[BIFF_STRLEN]; unsigned int vertNum, vertIdx, primNum, indxNum, cnum, ci; float cn; vertNum = sharpEdge ? 6*4 : 8; primNum = 1; indxNum = 6*4; if (limnPolyDataAlloc(pld, infoBitFlag, vertNum, indxNum, primNum)) { sprintf(err, "%s: couldn't allocate output", me); biffAdd(LIMN, err); return 1; } vertIdx = 0; cnum = sharpEdge ? 3 : 1; cn = AIR_CAST(float, sqrt(3.0)); for (ci=0; ci<cnum; ci++) { ELL_4V_SET(pld->xyzw + 4*vertIdx, -1, -1, -1, 1); vertIdx++; } for (ci=0; ci<cnum; ci++) { ELL_4V_SET(pld->xyzw + 4*vertIdx, -1, 1, -1, 1); vertIdx++; } for (ci=0; ci<cnum; ci++) { ELL_4V_SET(pld->xyzw + 4*vertIdx, 1, 1, -1, 1); vertIdx++; } for (ci=0; ci<cnum; ci++) { ELL_4V_SET(pld->xyzw + 4*vertIdx, 1, -1, -1, 1); vertIdx++; } for (ci=0; ci<cnum; ci++) { ELL_4V_SET(pld->xyzw + 4*vertIdx, -1, -1, 1, 1); vertIdx++; } for (ci=0; ci<cnum; ci++) { ELL_4V_SET(pld->xyzw + 4*vertIdx, -1, 1, 1, 1); vertIdx++; } for (ci=0; ci<cnum; ci++) { ELL_4V_SET(pld->xyzw + 4*vertIdx, 1, 1, 1, 1); vertIdx++; } for (ci=0; ci<cnum; ci++) { ELL_4V_SET(pld->xyzw + 4*vertIdx, 1, -1, 1, 1); vertIdx++; } vertIdx = 0; if (sharpEdge) { ELL_4V_SET(pld->indx + vertIdx, 0, 3, 6, 9); vertIdx += 4; ELL_4V_SET(pld->indx + vertIdx, 2, 14, 16, 5); vertIdx += 4; ELL_4V_SET(pld->indx + vertIdx, 4, 17, 18, 8); vertIdx += 4; ELL_4V_SET(pld->indx + vertIdx, 7, 19, 21, 10); vertIdx += 4; ELL_4V_SET(pld->indx + vertIdx, 1, 11, 23, 13); vertIdx += 4; ELL_4V_SET(pld->indx + vertIdx, 12, 22, 20, 15); vertIdx += 4; } else { ELL_4V_SET(pld->indx + vertIdx, 0, 1, 2, 3); vertIdx += 4; ELL_4V_SET(pld->indx + vertIdx, 0, 4, 5, 1); vertIdx += 4; ELL_4V_SET(pld->indx + vertIdx, 1, 5, 6, 2); vertIdx += 4; ELL_4V_SET(pld->indx + vertIdx, 2, 6, 7, 3); vertIdx += 4; ELL_4V_SET(pld->indx + vertIdx, 0, 3, 7, 4); vertIdx += 4; ELL_4V_SET(pld->indx + vertIdx, 4, 7, 6, 5); vertIdx += 4; } if ((1 << limnPolyDataInfoNorm) & infoBitFlag) { if (sharpEdge) { ELL_3V_SET(pld->norm + 3*0, 0, 0, -1); ELL_3V_SET(pld->norm + 3*3, 0, 0, -1); ELL_3V_SET(pld->norm + 3*6, 0, 0, -1); ELL_3V_SET(pld->norm + 3*9, 0, 0, -1); ELL_3V_SET(pld->norm + 3*2, -1, 0, 0); ELL_3V_SET(pld->norm + 3*5, -1, 0, 0); ELL_3V_SET(pld->norm + 3*14, -1, 0, 0); ELL_3V_SET(pld->norm + 3*16, -1, 0, 0); ELL_3V_SET(pld->norm + 3*4, 0, 1, 0); ELL_3V_SET(pld->norm + 3*8, 0, 1, 0); ELL_3V_SET(pld->norm + 3*17, 0, 1, 0); ELL_3V_SET(pld->norm + 3*18, 0, 1, 0); ELL_3V_SET(pld->norm + 3*7, 1, 0, 0); ELL_3V_SET(pld->norm + 3*10, 1, 0, 0); ELL_3V_SET(pld->norm + 3*19, 1, 0, 0); ELL_3V_SET(pld->norm + 3*21, 1, 0, 0); ELL_3V_SET(pld->norm + 3*1, 0, -1, 0); ELL_3V_SET(pld->norm + 3*11, 0, -1, 0); ELL_3V_SET(pld->norm + 3*13, 0, -1, 0); ELL_3V_SET(pld->norm + 3*23, 0, -1, 0); ELL_3V_SET(pld->norm + 3*12, 0, 0, 1); ELL_3V_SET(pld->norm + 3*15, 0, 0, 1); ELL_3V_SET(pld->norm + 3*20, 0, 0, 1); ELL_3V_SET(pld->norm + 3*22, 0, 0, 1); } else { ELL_3V_SET(pld->norm + 3*0, -cn, -cn, -cn); ELL_3V_SET(pld->norm + 3*1, -cn, cn, -cn); ELL_3V_SET(pld->norm + 3*2, cn, cn, -cn); ELL_3V_SET(pld->norm + 3*3, cn, -cn, -cn); ELL_3V_SET(pld->norm + 3*4, -cn, -cn, cn); ELL_3V_SET(pld->norm + 3*5, -cn, cn, cn); ELL_3V_SET(pld->norm + 3*6, cn, cn, cn); ELL_3V_SET(pld->norm + 3*7, cn, -cn, cn); } } pld->type[0] = limnPrimitiveQuads; pld->icnt[0] = indxNum; if ((1 << limnPolyDataInfoRGBA) & infoBitFlag) { for (vertIdx=0; vertIdx<pld->rgbaNum; vertIdx++) { ELL_4V_SET(pld->rgba + 4*vertIdx, 255, 255, 255, 255); } } return 0; }
int main(int argc, const char *argv[]) { const char *me; hestOpt *hopt=NULL; airArray *mop; double _tt[6], tt[7], ss, pp[3], qq[4], rot[9], mat1[9], mat2[9], tmp, evalA[3], evecA[9], evalB[3], evecB[9]; int roots; mop = airMopNew(); me = argv[0]; hestOptAdd(&hopt, NULL, "m00 m01 m02 m11 m12 m22", airTypeDouble, 6, 6, _tt, NULL, "symmtric matrix coeffs"); hestOptAdd(&hopt, "p", "vec", airTypeDouble, 3, 3, pp, "0 0 0", "rotation as P vector"); hestOptAdd(&hopt, "s", "scl", airTypeDouble, 1, 1, &ss, "1.0", "scaling"); 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); ELL_6V_COPY(tt + 1, _tt); tt[0] = 1.0; TEN_T_SCALE(tt, ss, tt); ELL_4V_SET(qq, 1, pp[0], pp[1], pp[2]); ELL_4V_NORM(qq, qq, tmp); ell_q_to_3m_d(rot, qq); printf("%s: rot\n", me); printf(" %g %g %g\n", rot[0], rot[1], rot[2]); printf(" %g %g %g\n", rot[3], rot[4], rot[5]); printf(" %g %g %g\n", rot[6], rot[7], rot[8]); TEN_T2M(mat1, tt); ell_3m_mul_d(mat2, rot, mat1); ELL_3M_TRANSPOSE_IP(rot, tmp); ell_3m_mul_d(mat1, mat2, rot); TEN_M2T(tt, mat1); printf("input matrix = \n %g %g %g\n %g %g\n %g\n", tt[1], tt[2], tt[3], tt[4], tt[5], tt[6]); printf("================== tenEigensolve_d ==================\n"); roots = tenEigensolve_d(evalA, evecA, tt); printf("%s roots\n", airEnumStr(ell_cubic_root, roots)); testeigen(tt, evalA, evecA); printf("================== new eigensolve ==================\n"); roots = evals(evalB, tt[1], tt[2], tt[3], tt[4], tt[5], tt[6]); printf("%s roots: %g %g %g\n", airEnumStr(ell_cubic_root, roots), evalB[0], evalB[1], evalB[2]); roots = evals_evecs(evalB, evecB, tt[1], tt[2], tt[3], tt[4], tt[5], tt[6]); printf("%s roots\n", airEnumStr(ell_cubic_root, roots)); testeigen(tt, evalB, evecB); airMopOkay(mop); return 0; }
int main(int argc, char *argv[]) { char *me, *outS; hestOpt *hopt; hestParm *hparm; airArray *mop; int fidx, aidx, num, frames; double psc, width[2], arrowWidth, lineWidth, angle, seglen, x0, y0, x1, y1, cc, ss; wheelPS wps; char filename[AIR_STRLEN_MED]; me = argv[0]; mop = airMopNew(); hparm = hestParmNew(); hparm->elideMultipleNonExistFloatDefault = AIR_TRUE; hopt = NULL; airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways); hestOptAdd(&hopt, "w", "arrowWidth lineWidth", airTypeDouble, 2, 2, width, "1.0 0.2", "widths"); hestOptAdd(&hopt, "n", "number", airTypeInt, 1, 1, &num, "10", "number of arrows"); hestOptAdd(&hopt, "f", "frames", airTypeInt, 1, 1, &frames, "10", "number of frames"); hestOptAdd(&hopt, "psc", "scale", airTypeDouble, 1, 1, &psc, "200", "scaling from world space to PostScript points"); hestOptAdd(&hopt, "o", "prefix", airTypeString, 1, 1, &outS, NULL, "prefix of file names"); hestParseOrDie(hopt, argc-1, argv+1, hparm, me, interInfo, AIR_TRUE, AIR_TRUE, AIR_TRUE); airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); for (fidx=0; fidx<frames; fidx++) { sprintf(filename, "%s%03d.eps", outS, fidx); if (!(wps.file = airFopen(filename, stdout, "wb"))) { fprintf(stderr, "%s: couldn't open output file\n", me); airMopError(mop); return 1; } lineWidth = width[0]; arrowWidth = width[1]; wps.psc = psc; ELL_4V_SET(wps.bbox, -0.45, -0.85, 1.1, 0.85); wheelPreamble(&wps); fprintf(wps.file, "0 setlinecap\n"); wheelGray(&wps, 0.4); wheelWidth(&wps, lineWidth); x0 = 0; y0 = 0; seglen = 1.0/num; angle = AIR_AFFINE(0, fidx, frames, 0, 2*AIR_PI); for (aidx=1; aidx<=num; aidx++) { cc = cos(angle*aidx)*seglen; ss = sin(angle*aidx)*seglen; x1 = x0 + 0.90*cc; y1 = y0 + 0.90*ss; wheelArrow(&wps, x0, y0, x1, y1, arrowWidth, arrowWidth*0.4); x0 += cc; y0 += ss; } wheelGray(&wps, 0.0); wheelArrow(&wps, 0, 0, x0, y0, arrowWidth, arrowWidth*0.4); wheelEpilog(&wps); airFclose(wps.file); } airMopOkay(mop); exit(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; }
int main(int argc, const char *argv[]) { const char *me; char *err, *outS; double eval[3], matA[9], matB[9], sval[3], uu[9], vv[9], escl[5], view[3]; float matAf[9], matBf[16]; float pp[3], qq[4], mR[9], len, gamma; float os, vs, rad, AB[2], ten[7]; hestOpt *hopt=NULL; airArray *mop; limnObject *obj; limnLook *look; int lookRod, lookSoid; float kadsRod[3], kadsSoid[3]; int gtype, partIdx=-1; /* sssh */ int res; FILE *file; me = argv[0]; hestOptAdd(&hopt, "sc", "evals", airTypeDouble, 3, 3, eval, "1 1 1", "original eigenvalues of tensor to be visualized"); 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, "vs", "view-dir scaling", airTypeFloat, 1, 1, &vs, "1", "scaling along view-direction (to show off bas-relief " "ambibuity of ellipsoids versus superquads)"); hestOptAdd(&hopt, "es", "extra scaling", airTypeDouble, 5, 5, escl, "2 1 0 0 1", "extra scaling specified with five values " "0:tensor|1:geometry|2:none vx vy vz scaling"); hestOptAdd(&hopt, "fr", "from (eye) point", airTypeDouble, 3, 3, &view, "4 4 4", "eye point, needed for non-unity \"-vs\""); hestOptAdd(&hopt, "gamma", "superquad sharpness", airTypeFloat, 1, 1, &gamma, "0", "how much to sharpen edges as a " "function of differences between eigenvalues"); hestOptAdd(&hopt, "g", "glyph shape", airTypeEnum, 1, 1, >ype, "sqd", "glyph to use; not all are implemented here", NULL, tenGlyphType); hestOptAdd(&hopt, "pp", "x y z", airTypeFloat, 3, 3, pp, "0 0 0", "transform: rotation identified by" "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, "pg", "ka kd ks", airTypeFloat, 3, 3, kadsSoid, "0.2 0.8 0.0", "phong coefficients for glyph"); hestOptAdd(&hopt, "pr", "ka kd ks", airTypeFloat, 3, 3, kadsRod, "1 0 0", "phong coefficients for black rods (if being drawn)"); 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(1000, AIR_TRUE); airMopAdd(mop, obj, (airMopper)limnObjectNix, airMopAlways); if (!( 0 == escl[0] || 1 == escl[0] || 2 == escl[0] )) { fprintf(stderr, "%s: escl[0] %g not 0, 1 or 2\n", me, escl[0]); airMopError(mop); return 1; } if (!(tenGlyphTypeBox == gtype || tenGlyphTypeSphere == gtype || tenGlyphTypeSuperquad == gtype)) { fprintf(stderr, "%s: got %s %s, but here only do %s, %s, or %s\n", me, tenGlyphType->name, airEnumStr(tenGlyphType, gtype), airEnumStr(tenGlyphType, tenGlyphTypeBox), airEnumStr(tenGlyphType, tenGlyphTypeSphere), airEnumStr(tenGlyphType, tenGlyphTypeSuperquad)); airMopError(mop); return 1; } /* create limnLooks for glyph and for rods */ lookSoid = limnObjectLookAdd(obj); look = obj->look + lookSoid; ELL_4V_SET(look->rgba, 1, 1, 1, 1); ELL_3V_COPY(look->kads, kadsSoid); look->spow = 0; lookRod = limnObjectLookAdd(obj); look = obj->look + lookRod; ELL_4V_SET(look->rgba, 0, 0, 0, 1); ELL_3V_COPY(look->kads, kadsRod); look->spow = 0; ELL_3M_IDENTITY_SET(matA); /* A = I */ ELL_3V_SCALE(eval, os, eval); ELL_3M_SCALE_SET(matB, eval[0], eval[1], eval[2]); /* B = diag(eval) */ ell_3m_post_mul_d(matA, matB); /* A = B*A = diag(eval) */ if (0 == escl[0]) { scalingMatrix(matB, escl + 1, escl[4]); ell_3m_post_mul_d(matA, matB); } if (1 != vs) { if (!ELL_3V_LEN(view)) { fprintf(stderr, "%s: need non-zero view for vs %g != 1\n", me, vs); airMopError(mop); return 1; } scalingMatrix(matB, view, vs); /* the scaling along the view direction is a symmetric matrix, but applying that scaling to the symmetric input tensor is not necessarily symmetric */ ell_3m_post_mul_d(matA, matB); /* A = B*A */ } /* so we do an SVD to get rotation U and the scalings sval[] */ /* U * diag(sval) * V */ ell_3m_svd_d(uu, sval, vv, matA, AIR_TRUE); /* fprintf(stderr, "%s: ____________________________________\n", me); fprintf(stderr, "%s: mat = \n", me); ell_3m_print_d(stderr, matA); fprintf(stderr, "%s: uu = \n", me); ell_3m_print_d(stderr, uu); ELL_3M_TRANSPOSE(matC, uu); ELL_3M_MUL(matB, uu, matC); fprintf(stderr, "%s: uu * uu^T = \n", me); ell_3m_print_d(stderr, matB); fprintf(stderr, "%s: sval = %g %g %g\n", me, sval[0], sval[1], sval[2]); fprintf(stderr, "%s: vv = \n", me); ell_3m_print_d(stderr, vv); ELL_3M_MUL(matB, vv, vv); fprintf(stderr, "%s: vv * vv^T = \n", me); ELL_3M_TRANSPOSE(matC, vv); ELL_3M_MUL(matB, vv, matC); ell_3m_print_d(stderr, matB); ELL_3M_IDENTITY_SET(matA); ell_3m_pre_mul_d(matA, uu); ELL_3M_SCALE_SET(matB, sval[0], sval[1], sval[2]); ell_3m_pre_mul_d(matA, matB); ell_3m_pre_mul_d(matA, vv); fprintf(stderr, "%s: uu * diag(sval) * vv = \n", me); ell_3m_print_d(stderr, matA); fprintf(stderr, "%s: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", me); */ /* now create symmetric matrix out of U and sval */ /* A = I */ ELL_3M_IDENTITY_SET(matA); ell_3m_pre_mul_d(matA, uu); /* A = A*U = I*U = U */ ELL_3M_SCALE_SET(matB, sval[0], sval[1], sval[2]); /* B = diag(sval) */ ell_3m_pre_mul_d(matA, matB); /* A = U*diag(sval) */ ELL_3M_TRANSPOSE(matB, uu); ell_3m_pre_mul_d(matA, matB); /* A = U*diag(sval)*U^T */ TEN_M2T(ten, matA); partIdx = soidDoit(obj, lookSoid, gtype, gamma, res, (AIR_EXISTS(AB[0]) && AIR_EXISTS(AB[1])) ? AB : NULL, ten); if (1 == escl[0]) { scalingMatrix(matB, escl + 1, escl[4]); ELL_43M_INSET(matBf, matB); limnObjectPartTransform(obj, partIdx, matBf); } /* this is a rotate on the geomtry; nothing to do with the tensor */ ELL_4V_SET(qq, 1, pp[0], pp[1], pp[2]); ELL_4V_NORM(qq, qq, len); ell_q_to_3m_f(mR, qq); ELL_43M_INSET(matBf, mR); limnObjectPartTransform(obj, partIdx, matBf); if (rad) { partIdx = limnObjectCylinderAdd(obj, lookRod, 0, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, (1-eval[0])/2, rad, rad); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, (1+eval[0])/2, 0.0, 0.0); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); partIdx = limnObjectCylinderAdd(obj, lookRod, 0, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, (1-eval[0])/2, rad, rad); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, -(1+eval[0])/2, 0.0, 0.0); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); partIdx = limnObjectCylinderAdd(obj, lookRod, 1, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, rad, (1-eval[1])/2, rad); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, 0.0, (1+eval[1])/2, 0.0); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); partIdx = limnObjectCylinderAdd(obj, lookRod, 1, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, rad, (1-eval[1])/2, rad); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, 0.0, -(1+eval[1])/2, 0.0); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); partIdx = limnObjectCylinderAdd(obj, lookRod, 2, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, rad, rad, (1-eval[2])/2); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, 0.0, 0.0, (1+eval[2])/2); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); partIdx = limnObjectCylinderAdd(obj, lookRod, 2, res); ELL_4M_IDENTITY_SET(matAf); ELL_4M_SCALE_SET(matBf, rad, rad, (1-eval[2])/2); ell_4m_post_mul_f(matAf, matBf); ELL_4M_TRANSLATE_SET(matBf, 0.0, 0.0, -(1+eval[2])/2); ell_4m_post_mul_f(matAf, matBf); limnObjectPartTransform(obj, partIdx, matAf); } 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; }
/* ** unlike the thing above, this one assumes that the quaternions in qq ** have already been normalized, and, that the sum of wght[] is 1.0 */ int ell_q_avgN_d(double mm[4], unsigned int *iterP, const double *qq, double *qlog, const double *wght, const unsigned int NN, const double eps, const unsigned int maxIter) { static const char me[]="ell_q_avgN_d"; double tmp, qdiv[4], elen; unsigned int ii, iter; /* iterP optional */ /* wght optional, to signify equal 1/NN weighting for all */ if (!( mm && qq )) { biffAddf(ELL, "%s: got NULL pointer", me); return 1; } if (!( eps >= 0 )) { biffAddf(ELL, "%s: need eps >= 0 (not %g)", me, eps); return 1; } /* initialize with euclidean mean */ ELL_4V_SET(mm, 0, 0, 0, 0); for (ii=0; ii<NN; ii++) { double ww; ww = wght ? wght[ii] : 1.0/NN; ELL_4V_SCALE_INCR(mm, ww, qq + 4*ii); } ELL_4V_NORM(mm, mm, tmp); iter = 0; do { double logavg[4], qexp[4]; /* take log of everyone */ for (ii=0; ii<NN; ii++) { ell_q_div_d(qdiv, mm, qq + 4*ii); /* div = mm^1 * qq[ii] */ ell_q_log_d(qlog + 4*ii, qdiv); } /* average, and find length */ ELL_4V_SET(logavg, 0, 0, 0, 0); for (ii=0; ii<NN; ii++) { double ww; ww = wght ? wght[ii] : 1.0/NN; ELL_4V_SCALE_INCR(logavg, ww, qlog + 4*ii); } elen = ELL_4V_LEN(logavg); /* use exp to put it back on S^3 */ ell_q_exp_d(qexp, logavg); ell_q_mul_d(mm, mm, qexp); iter++; } while ((!maxIter || iter < maxIter) && elen > eps); if (elen > eps) { biffAddf(ELL, "%s: still have error %g (> eps %g) after max %d iters", me, elen, eps, maxIter); return 1; } if (iterP) { *iterP = iter; } return 0; }
/* ******** limnCameraPathMake ** ** uses limnSplines to do camera paths based on key-frames ** ** output: cameras at all "numFrames" frames are set in the ** PRE-ALLOCATED array of output cameras, "cam". ** ** input: ** keycam: array of keyframe cameras ** time: times associated with the key frames ** ---> both of these arrays are length "numKeys" <--- ** trackWhat: takes values from the limnCameraPathTrack* enum ** quatType: spline to control camera orientations. This is needed for ** tracking at or from, but not needed for limnCameraPathTrackBoth. ** This is the only limnSplineTypeSpec* argument that can be NULL. ** posType: spline to control whichever of from, at, and up are needed for ** the given style of tracking. ** distType: spline to control neer, faar, dist: positions of near clipping, ** far clipping, and image plane, as well as the ** distance between from and at (which is used if not doing ** limnCameraPathTrackBoth) ** viewType: spline to control fov (and aspect, if you're crazy) ** ** NOTE: The "atRelative", "orthographic", and "rightHanded" fields ** are copied from keycam[0] into all output cam[i], but you still need ** to correctly set them for all keycam[i] for limnCameraUpdate to work ** as expected. Also, for the sake of simplicity, this function only works ** with fov and aspect, instead of {u,v}Range, and hence both "fov" and ** "aspect" need to set in *all* the keycams, even if neither of them ** ever changes! */ int limnCameraPathMake(limnCamera *cam, int numFrames, limnCamera *keycam, double *time, int numKeys, int trackWhat, limnSplineTypeSpec *quatType, limnSplineTypeSpec *posType, limnSplineTypeSpec *distType, limnSplineTypeSpec *viewType) { static const char me[]="limnCameraPathMake"; char which[AIR_STRLEN_MED]; airArray *mop; Nrrd *nquat, *nfrom, *natpt, *nupvc, *ndist, *nfova, *ntime, *nsample; double fratVec[3], *quat, *from, *atpt, *upvc, *dist, *fova, W2V[9], N[3], fratDist; limnSpline *timeSpline, *quatSpline, *fromSpline, *atptSpline, *upvcSpline, *distSpline, *fovaSpline; limnSplineTypeSpec *timeType; int ii, E; if (!( cam && keycam && time && posType && distType && viewType )) { biffAddf(LIMN, "%s: got NULL pointer", me); return 1; } if (!( AIR_IN_OP(limnCameraPathTrackUnknown, trackWhat, limnCameraPathTrackLast) )) { biffAddf(LIMN, "%s: trackWhat %d not in valid range [%d,%d]", me, trackWhat, limnCameraPathTrackUnknown+1, limnCameraPathTrackLast-1); return 1; } if (limnCameraPathTrackBoth != trackWhat && !quatType) { biffAddf(LIMN, "%s: need the quaternion limnSplineTypeSpec if not " "doing trackBoth", me); return 1; } /* create and allocate nrrds. For the time being, we're allocating more different nrrds, and filling their contents, than we need to-- nquat is not needed if we're doing limnCameraPathTrackBoth, for example. However, we do make an effort to only do the spline evaluation on the things we actually need to know. */ mop = airMopNew(); airMopAdd(mop, nquat = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nfrom = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, natpt = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nupvc = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, ndist = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, nfova = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); airMopAdd(mop, ntime = nrrdNew(), (airMopper)nrrdNix, airMopAlways); if (nrrdWrap_va(ntime, time, nrrdTypeDouble, 1, AIR_CAST(size_t, numKeys))) { biffMovef(LIMN, NRRD, "%s: trouble wrapping time values", me); airMopError(mop); return 1; } airMopAdd(mop, nsample = nrrdNew(), (airMopper)nrrdNuke, airMopAlways); timeType = limnSplineTypeSpecNew(limnSplineTypeTimeWarp); airMopAdd(mop, timeType, (airMopper)limnSplineTypeSpecNix, airMopAlways); if (nrrdMaybeAlloc_va(nquat, nrrdTypeDouble, 2, AIR_CAST(size_t, 4), AIR_CAST(size_t, numKeys)) || nrrdMaybeAlloc_va(nfrom, nrrdTypeDouble, 2, AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys)) || nrrdMaybeAlloc_va(natpt, nrrdTypeDouble, 2, AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys)) || nrrdMaybeAlloc_va(nupvc, nrrdTypeDouble, 2, AIR_CAST(size_t, 3), AIR_CAST(size_t, numKeys)) || nrrdMaybeAlloc_va(ndist, nrrdTypeDouble, 2, AIR_CAST(size_t, 4), AIR_CAST(size_t, numKeys)) || nrrdMaybeAlloc_va(nfova, nrrdTypeDouble, 2, AIR_CAST(size_t, 2), AIR_CAST(size_t, numKeys))) { biffMovef(LIMN, NRRD, "%s: couldn't allocate buffer nrrds", me); airMopError(mop); return 1; } quat = (double*)(nquat->data); from = (double*)(nfrom->data); atpt = (double*)(natpt->data); upvc = (double*)(nupvc->data); dist = (double*)(ndist->data); fova = (double*)(nfova->data); /* check cameras, and put camera information into nrrds */ for (ii=0; ii<numKeys; ii++) { if (limnCameraUpdate(keycam + ii)) { biffAddf(LIMN, "%s: trouble with camera at keyframe %d\n", me, ii); airMopError(mop); return 1; } if (!( AIR_EXISTS(keycam[ii].fov) && AIR_EXISTS(keycam[ii].aspect) )) { biffAddf(LIMN, "%s: fov, aspect not both defined on keyframe %d", me, ii); airMopError(mop); return 1; } ell_4m_to_q_d(quat + 4*ii, keycam[ii].W2V); if (ii) { if (0 > ELL_4V_DOT(quat + 4*ii, quat + 4*(ii-1))) { ELL_4V_SCALE(quat + 4*ii, -1, quat + 4*ii); } } ELL_3V_COPY(from + 3*ii, keycam[ii].from); ELL_3V_COPY(atpt + 3*ii, keycam[ii].at); ELL_3V_COPY(upvc + 3*ii, keycam[ii].up); ELL_3V_SUB(fratVec, keycam[ii].from, keycam[ii].at); fratDist = ELL_3V_LEN(fratVec); ELL_4V_SET(dist + 4*ii, fratDist, keycam[ii].neer, keycam[ii].dist, keycam[ii].faar); ELL_2V_SET(fova + 2*ii, keycam[ii].fov, keycam[ii].aspect); } /* create splines from nrrds */ if (!( (strcpy(which, "quaternion"), quatSpline = limnSplineCleverNew(nquat, limnSplineInfoQuaternion, quatType)) && (strcpy(which, "from point"), fromSpline = limnSplineCleverNew(nfrom, limnSplineInfo3Vector, posType)) && (strcpy(which, "at point"), atptSpline = limnSplineCleverNew(natpt, limnSplineInfo3Vector, posType)) && (strcpy(which, "up vector"), upvcSpline = limnSplineCleverNew(nupvc, limnSplineInfo3Vector, posType)) && (strcpy(which, "plane distances"), distSpline = limnSplineCleverNew(ndist, limnSplineInfo4Vector, distType)) && (strcpy(which, "field-of-view"), fovaSpline = limnSplineCleverNew(nfova, limnSplineInfo2Vector, viewType)) && (strcpy(which, "time warp"), timeSpline = limnSplineCleverNew(ntime, limnSplineInfoScalar, timeType)) )) { biffAddf(LIMN, "%s: trouble creating %s spline", me, which); airMopError(mop); return 1; } airMopAdd(mop, quatSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, fromSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, atptSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, upvcSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, distSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, fovaSpline, (airMopper)limnSplineNix, airMopAlways); airMopAdd(mop, timeSpline, (airMopper)limnSplineNix, airMopAlways); /* evaluate splines */ E = AIR_FALSE; if (!E) E |= limnSplineSample(nsample, timeSpline, limnSplineMinT(timeSpline), numFrames, limnSplineMaxT(timeSpline)); quat = NULL; from = NULL; atpt = NULL; upvc = NULL; switch(trackWhat) { case limnCameraPathTrackAt: if (!E) E |= limnSplineNrrdEvaluate(natpt, atptSpline, nsample); if (!E) atpt = (double*)(natpt->data); if (!E) E |= limnSplineNrrdEvaluate(nquat, quatSpline, nsample); if (!E) quat = (double*)(nquat->data); break; case limnCameraPathTrackFrom: if (!E) E |= limnSplineNrrdEvaluate(nfrom, fromSpline, nsample); if (!E) from = (double*)(nfrom->data); if (!E) E |= limnSplineNrrdEvaluate(nquat, quatSpline, nsample); if (!E) quat = (double*)(nquat->data); break; case limnCameraPathTrackBoth: if (!E) E |= limnSplineNrrdEvaluate(nfrom, fromSpline, nsample); if (!E) from = (double*)(nfrom->data); if (!E) E |= limnSplineNrrdEvaluate(natpt, atptSpline, nsample); if (!E) atpt = (double*)(natpt->data); if (!E) E |= limnSplineNrrdEvaluate(nupvc, upvcSpline, nsample); if (!E) upvc = (double*)(nupvc->data); break; } dist = NULL; if (!E) E |= limnSplineNrrdEvaluate(ndist, distSpline, nsample); if (!E) dist = (double*)(ndist->data); fova = NULL; if (!E) E |= limnSplineNrrdEvaluate(nfova, fovaSpline, nsample); if (!E) fova = (double*)(nfova->data); if (E) { biffAddf(LIMN, "%s: trouble evaluating splines", me); airMopError(mop); return 1; } /* copy information from nrrds back into cameras */ for (ii=0; ii<numFrames; ii++) { cam[ii].atRelative = keycam[0].atRelative; cam[ii].orthographic = keycam[0].orthographic; cam[ii].rightHanded = keycam[0].rightHanded; if (limnCameraPathTrackBoth == trackWhat) { ELL_3V_COPY(cam[ii].from, from + 3*ii); ELL_3V_COPY(cam[ii].at, atpt + 3*ii); ELL_3V_COPY(cam[ii].up, upvc + 3*ii); } else { fratDist = (dist + 4*ii)[0]; ell_q_to_3m_d(W2V, quat + 4*ii); ELL_3MV_ROW1_GET(cam[ii].up, W2V); if (cam[ii].rightHanded) { ELL_3V_SCALE(cam[ii].up, -1, cam[ii].up); } ELL_3MV_ROW2_GET(N, W2V); if (limnCameraPathTrackFrom == trackWhat) { ELL_3V_COPY(cam[ii].from, from + 3*ii); ELL_3V_SCALE_ADD2(cam[ii].at, 1.0, cam[ii].from, fratDist, N); } else { ELL_3V_COPY(cam[ii].at, atpt + 3*ii); ELL_3V_SCALE_ADD2(cam[ii].from, 1.0, cam[ii].at, -fratDist, N); } } cam[ii].neer = (dist + 4*ii)[1]; cam[ii].dist = (dist + 4*ii)[2]; cam[ii].faar = (dist + 4*ii)[3]; cam[ii].fov = (fova + 2*ii)[0]; cam[ii].aspect = (fova + 2*ii)[1]; if (limnCameraUpdate(cam + ii)) { biffAddf(LIMN, "%s: trouble with output camera %d\n", me, ii); 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; }
/* ******** 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; }