예제 #1
0
파일: quat.c 프로젝트: CIBC-Internal/teem
/*
** 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;
}
예제 #2
0
파일: quat.c 프로젝트: CIBC-Internal/teem
void
ell_3m_to_q_d(double q[4], const double m[9]) {
  _ELL_M_TO_Q(double, 0, 1, 2,    3, 4, 5,    6, 7, 8);
  ELL_4V_NORM(q, q, len);
}
예제 #3
0
파일: quat.c 프로젝트: CIBC-Internal/teem
void
ell_q_to_4m_d(double m[16], const double q[4]) {
  double u[4], w=0.0, x=0.0, y=0.0, z=0.0;
  ELL_4V_NORM(u, q, w);
  _ELL_Q_TO_4M(double);
}
예제 #4
0
파일: quat.c 프로젝트: CIBC-Internal/teem
int
ell_q_avg4_d(double m[4], unsigned int *iterP,
             const double _q1[4], const double _q2[4],
             const double _q3[4], const double _q4[4],
             const double _wght[4],
             const double eps, const unsigned int maxIter) {
  static const char me[]="ell_q_avg4_d";
  double N, elen, a[4], b[4], c[4], d[4],
    tmp[4], la[4], lb[4], lc[4], ld[4], u[4], wght[4];
  unsigned int iter;

  /* *iterP optional */
  if (!( m && _q1 && _q2 && _q3 && _q4 && _wght )) {
    biffAddf(ELL, "%s: got NULL pointer", me);
    return 1;
  }
  if (!( eps >= 0 )) {
    biffAddf(ELL, "%s: need eps >= 0 (not %g)", me, eps);
    return 1;
  }

  /* normalize (wrt L2) all given quaternions */
  ELL_4V_NORM(a, _q1, N);
  ELL_4V_NORM(b, _q2, N);
  ELL_4V_NORM(c, _q3, N);
  ELL_4V_NORM(d, _q4, N);

  /* normalize (wrt L1) the given weights */
  ELL_4V_COPY(wght, _wght);
  N = wght[0] + wght[1] + wght[2] + wght[3];
  ELL_4V_SCALE(wght, 1.0/N, wght);

  /* initialize mean to normalized euclidean mean */
  ELL_4V_SCALE_ADD4(m, wght[0], a, wght[1], b, wght[2], c, wght[3], d);
  ELL_4V_NORM(m, m, N);

  iter = 0;
  do {
    /* take log of everyone */
    ell_q_div_d(tmp, m, a); ell_q_log_d(la, tmp);
    ell_q_div_d(tmp, m, b); ell_q_log_d(lb, tmp);
    ell_q_div_d(tmp, m, c); ell_q_log_d(lc, tmp);
    ell_q_div_d(tmp, m, d); ell_q_log_d(ld, tmp);
    /* average, and find length */
    ELL_4V_SCALE_ADD4(u, wght[0], la, wght[1], lb, wght[2], lc, wght[3], ld);
    elen = ELL_4V_LEN(u);
    /* use exp to put it back on S^3 */
    ell_q_exp_d(tmp, u); ell_q_mul_d(m, m, tmp);
    iter++;
  } while ((!maxIter || iter < maxIter) && elen > eps);
  if (elen > eps) {
    biffAddf(ELL, "%s: still have error %g after max %d iters", me,
             elen, maxIter);
    return 1;
  }

  if (iterP) {
    *iterP = iter;
  }
  return 0;
}
예제 #5
0
파일: qglox.c 프로젝트: CIBC-Internal/teem
/*
** This does (non-optionally) use biff, to report convergence failures
**
** we do in fact require non-NULL tip, because it holds the buffers we need
*/
int
_tenQGLInterpNEvec(double evecOut[9],
                   const double *evecIn, /* size 9 -by- NN */
                   const double *wght,   /* size NN */
                   unsigned int NN,
                   tenInterpParm *tip) {
  static const char me[]="_tenQGLInterpNEvec";
  double qOut[4], maxWght, len, /* odsum, */ dsum, rot[9];
  unsigned int ii, centerIdx=0, fix, qiter;

  if (!( evecOut && evecIn && tip )) {
    biffAddf(TEN, "%s: got NULL pointer", me);
    return 1;
  }
  /* convert to quaternions */
  for (ii=0; ii<NN; ii++) {
    ELL_3M_TRANSPOSE(rot, evecIn + 9*ii);
    ell_3m_to_q_d(tip->qIn + 4*ii, rot);
  }
  /* HEY: what should this be used for?  variable odsum set but not used */
  /* odsum = _tenQGL_q_interdot(&centerIdx, tip->qIn, tip->qInter, NN); */

  /* find quaternion with maximal weight, use it as is (decree that
     its the right representative), and then align rest with that.
     This is actually principled; symmetry allows it */
  centerIdx = 0;
  if (wght) {
    maxWght = wght[centerIdx];
    for (ii=1; ii<NN; ii++) {
      if (wght[ii] > maxWght) {
        centerIdx = ii;
        maxWght = wght[centerIdx];
      }
    }
  }
  for (ii=0; ii<NN; ii++) {
    if (ii == centerIdx) {
      continue;
    }
    _tenQGL_q_align(tip->qIn + 4*ii, tip->qIn + 4*centerIdx, tip->qIn + 4*ii);
  }
  dsum = _tenQGL_q_interdot(&centerIdx, tip->qIn, tip->qInter, NN);

  /* try to settle on tightest set of representatives */
  qiter = 0;
  do {
    fix = 0;
    for (ii=0; ii<NN; ii++) {
      unsigned int ff;
      if (ii == centerIdx) {
        continue;
      }
      ff = _tenQGL_q_align(tip->qIn + 4*ii, tip->qIn + 4*centerIdx,
                           tip->qIn + 4*ii);
      fix = AIR_MAX(fix, ff);
    }
    dsum = _tenQGL_q_interdot(&centerIdx, tip->qIn, tip->qInter, NN);
    if (tip->maxIter && qiter > tip->maxIter) {
      biffAddf(TEN, "%s: q tightening unconverged after %u iters; "
               "interdot = %g -> maxfix = %u; center = %u\n",
               me, tip->maxIter, dsum, fix, centerIdx);
      return 1;
    }
    qiter++;
  } while (fix);
  /*
  fprintf(stderr, "!%s: dsum %g --%u--> %g\n", me, odsum, qiter, dsum);
  */
  /* make sure they're normalized */
  for (ii=0; ii<NN; ii++) {
    ELL_4V_NORM(tip->qIn + 4*ii, tip->qIn + 4*ii, len);
  }

  /* compute iterated weighted mean, stored in qOut */
  if (ell_q_avgN_d(qOut, &qiter, tip->qIn, tip->qBuff, wght,
                   NN, tip->convEps, tip->maxIter)) {
    biffMovef(TEN, ELL, "%s: problem doing quaternion mean", me);
    return 1;
  }
  /*
  fprintf(stderr, "!%s: q avg converged in %u\n", me, qiter);
  */

  /* finish, convert back to evec */
  ell_q_to_3m_d(rot, qOut);
  ELL_3M_TRANSPOSE(evecOut, rot);

  return 0;
}
예제 #6
0
파일: quat.c 프로젝트: CIBC-Internal/teem
void
ell_4m_to_q_d(double q[4], const double m[16]) {
  _ELL_M_TO_Q(double, 0, 1, 2,    4, 5, 6,    8, 9, 10);
  ELL_4V_NORM(q, q, len);
}
예제 #7
0
파일: soid.c 프로젝트: BRAINSia/teem
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;
}
예제 #8
0
파일: tsoid.c 프로젝트: BRAINSia/teem
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, &gtype, "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;
}
예제 #9
0
파일: tsoid.c 프로젝트: CIBC-Internal/teem
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;
}
예제 #10
0
파일: teigen.c 프로젝트: BRAINSia/teem
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;
}
예제 #11
0
파일: csim.c 프로젝트: ryanfb/teem-parallel
static int
csimDo(double tm[7], double tcov[21], double rm[3], double rv[3],
       Nrrd *ntbuff, tenEstimateContext *tec, double *dwibuff, double sigma,
       double bvalue, double B0, unsigned int NN, int randrot,
       double _tenOrig[7]) {
  char me[]="csimDo", err[BIFF_STRLEN];
  double *tbuff;
  unsigned int II, taa, tbb, cc;

  if (!(ntbuff
        && ntbuff->data
        && 2 == ntbuff->dim
        && 7 == ntbuff->axis[0].size
        && NN == ntbuff->axis[1].size)) {
    sprintf(err, "%s: ntbuff not allocated for 2-by-%u array of %s", me,
            NN, airEnumStr(nrrdType, nrrdTypeDouble));
    biffAdd(TEN, err); return 1;
  }

  /* find all tensors from simulated DWIs */
  tbuff = AIR_CAST(double *, ntbuff->data);
  for (II=0; II<NN; II++) {
    double tenOrig[7], rotf[9], rotb[9], matA[9], matB[9], qq[4], tmp;
    ELL_3M_IDENTITY_SET(rotf); /* sssh warnings */
    ELL_3M_IDENTITY_SET(rotb); /* sssh warnings */

    if (randrot) {
      if (1) {
        double eval[3], evec[9], eps, ma[9], mb[9], rf[9], rb[9];
        tenEigensolve_d(eval, evec, _tenOrig);
        airNormalRand(&eps, NULL);
        ell_aa_to_3m_d(rf, 0*eps/20, evec + 0);
        TEN_T_SCALE_INCR(_tenOrig, 0*eps/30, _tenOrig);
        TEN_T2M(ma, _tenOrig);
        ELL_3M_TRANSPOSE(rb, rf);
        ELL_3M_MUL(mb, ma, rf);
        ELL_3M_MUL(ma, rb, mb);
        TEN_M2T(_tenOrig, ma);
      }
      TEN_T2M(matA, _tenOrig);
      airNormalRand(qq+0, qq+1);
      airNormalRand(qq+2, qq+3);
      ELL_4V_NORM(qq, qq, tmp);
      ell_q_to_3m_d(rotf, qq);
      ELL_3M_TRANSPOSE(rotb, rotf);
      ELL_3M_MUL(matB, matA, rotf);
      ELL_3M_MUL(matA, rotb, matB);
      TEN_M2T(tenOrig, matA);
    } else {
      TEN_T_COPY(tenOrig, _tenOrig);
    }
    if (tenEstimate1TensorSimulateSingle_d(tec, dwibuff, sigma,
                                           bvalue, B0, tenOrig)
        || tenEstimate1TensorSingle_d(tec, tbuff, dwibuff)) {
      sprintf(err, "%s: trouble on exp %u/%u", me, II, NN);
      biffAdd(TEN, err); return 1;
    }
    if (randrot) {
      TEN_T2M(matA, tbuff);
      ELL_3M_MUL(matB, matA, rotb);
      ELL_3M_MUL(matA, rotf, matB);
      TEN_M2T(tbuff, matA);
    } /* else we leave tbuff as it is */
    /*
    if (_tenOrig[0] > 0.5) {
      double tdiff[7];
      TEN_T_SUB(tdiff, _tenOrig, tbuff);
      fprintf(stderr, "!%s: %g\n"
              "         (%g) %g,%g,%g  %g,%g  %g\n"
              "         (%g) %g,%g,%g  %g,%g  %g\n", 
              me, TEN_T_NORM(tdiff),
              _tenOrig[0], _tenOrig[1], _tenOrig[2], _tenOrig[3], _tenOrig[4], 
              _tenOrig[5], _tenOrig[6], 
              tbuff[0], tbuff[1], tbuff[2], tbuff[3], tbuff[4],
              tbuff[5], tbuff[6]);
    }
    */
    tbuff += 7;
  }

  /* find mean tensor, and mean R_i */
  tbuff = AIR_CAST(double *, ntbuff->data);
  TEN_T_SET(tm, 0, 0, 0, 0, 0, 0, 0);
  ELL_3V_SET(rm, 0, 0, 0);
  for (II=0; II<NN; II++) {
    TEN_T_INCR(tm, tbuff);
    rm[0] += sqrt(_tenAnisoTen_d[tenAniso_S](tbuff));
    rm[1] += _tenAnisoTen_d[tenAniso_FA](tbuff);
    rm[2] += _tenAnisoTen_d[tenAniso_Mode](tbuff);
    tbuff += 7;
  }
  rm[0] /= NN;
  rm[1] /= NN;
  rm[2] /= NN;
  TEN_T_SCALE(tm, 1.0/NN, tm);

  /* accumulate covariance tensor, and R_i variances */
  for (cc=0; cc<21; cc++) {
    tcov[cc] = 0;
  }
  ELL_3V_SET(rv, 0, 0, 0);
  tbuff = AIR_CAST(double *, ntbuff->data);
  for (II=0; II<NN; II++) {
    double r[3];
    r[0] = sqrt(_tenAnisoTen_d[tenAniso_S](tbuff));
    r[1] = _tenAnisoTen_d[tenAniso_FA](tbuff);
    r[2] = _tenAnisoTen_d[tenAniso_Mode](tbuff);
    cc = 0;
    rv[0] += (r[0] - rm[0])*(r[0] - rm[0])/(NN-1);
    rv[1] += (r[1] - rm[1])*(r[1] - rm[1])/(NN-1);
    rv[2] += (r[2] - rm[2])*(r[2] - rm[2])/(NN-1);
    for (taa=0; taa<6; taa++) {
      for (tbb=taa; tbb<6; tbb++) {
        tcov[cc] += (10000*(tbuff[taa+1]-tm[taa+1])
                     *10000*(tbuff[tbb+1]-tm[tbb+1])/(NN-1));
        cc++;
      }
    }
    tbuff += 7;
  }

  return 0;
}