Example #1
0
/*
******** airArrayLenIncr()
**
** Like airArrayLenSet, but works with an increment instead of an
** absolute length.  Return value is different:
**             got NULL: return 0
**     allocation error: return 0, and a->data set to NULL
**  no error, delta > 0: return index of 1st element in newly allocated
**                       segment (a->len before length was increased)
** no error, delta <= 0: return 0, and a->data unchanged
**
** HEY: it is apparently not clear how to do error checking (aside from
** looking at a->data) when there was NO data previously allocated, and the
** first index of the newly allocated data is zero.
*/
unsigned int
airArrayLenIncr(airArray *a, int delta) {
  /* char me[]="airArrayLenIncr"; */
  unsigned int oldlen, ret, negdel;

  if (!a) {
    return 0;
  }
  negdel = (delta < 0
            ? AIR_UINT(-delta)
            : 0);
  if (delta < 0 && negdel > a->len) {
    /* error: asked for newlength to be negative */
    airArrayLenSet(a, 0);
    return 0;
  }
  oldlen = a->len;
  airArrayLenSet(a, (delta >= 0
                     ? oldlen + AIR_UINT(delta)
                     : oldlen - negdel));
  if (!a->data) {
    /* allocation error */
    ret = 0;
  } else {
    ret = (delta <= 0 ? 0 : oldlen);
  }

  return ret;
}
Example #2
0
/*
******** tenGradientJitter
**
** moves all gradients by amount dist on tangent plane, in a random
** direction, and then renormalizes. The distance is a fraction
** of the ideal edge length (via tenGradientIdealEdge)
*/
int
tenGradientJitter(Nrrd *nout, const Nrrd *nin, double dist) {
  static const char me[]="tenGradientJitter";
  double *grad, perp0[3], perp1[3], len, theta, cc, ss, edge;
  unsigned int gi, num;

  if (nrrdConvert(nout, nin, nrrdTypeDouble)) {
    biffMovef(TEN, NRRD, "%s: trouble converting input to double", me);
    return 1;
  }
  if (tenGradientCheck(nout, nrrdTypeDouble, 3)) {
    biffAddf(TEN, "%s: didn't get valid gradients", me);
    return 1;
  }
  grad = AIR_CAST(double*, nout->data);
  num = AIR_UINT(nout->axis[1].size);
  /* HEY: possible confusion between single and not */
  edge = tenGradientIdealEdge(num, AIR_FALSE);
  for (gi=0; gi<num; gi++) {
    ELL_3V_NORM(grad, grad, len);
    ell_3v_perp_d(perp0, grad);
    ELL_3V_CROSS(perp1, perp0, grad);
    theta = AIR_AFFINE(0, airDrandMT(), 1, 0, 2*AIR_PI);
    cc = dist*edge*cos(theta);
    ss = dist*edge*sin(theta);
    ELL_3V_SCALE_ADD3(grad, 1.0, grad, cc, perp0, ss, perp1);
    ELL_3V_NORM(grad, grad, len);
    grad += 3;
  }

  return 0;
}
Example #3
0
int
alanTensorSet(alanContext *actx, Nrrd *nten, int oversample) {
  static const char me[]="alanTensorSet";

  if (!( actx && nten )) {
    biffAddf(ALAN, "%s: got NULL pointer", me);
    return 1;
  }
  DIM_SET;
  if (!( oversample > 0 )) {
    biffAddf(ALAN, "%s: oversample %d invalid", me, oversample);
    return 1;
  }
  if (2 == actx->dim) {
    if (!( 3 == nten->dim && 4 == nten->axis[0].size )) {
      biffAddf(ALAN, "%s: didn't get 3-D (4,X,Y) nrrd", me);
      return 1;
    }
  } else {
    if (!( 4 == nten->dim && 7 == nten->axis[0].size )) {
      biffAddf(ALAN, "%s: didn't get 4-D (7,X,Y,Z) nrrd", me);
      return 1;
    }
  }

  if (1 != oversample) {
    biffAddf(ALAN, "%s: sorry, can only handle oversample==1 now", me);
    return 1;
  }

  actx->nten = nrrdNuke(actx->nten);
  actx->nten = nrrdNew();
  if (nrrdConvert(actx->nten, nten, alan_nt)) {
    biffMovef(ALAN, NRRD, "%s: trouble converting tensors to alan_t", me);
    return 1;
  }
  actx->size[0] = AIR_UINT(oversample*nten->axis[1].size);
  actx->size[1] = AIR_UINT(oversample*nten->axis[2].size);
  if (3 == actx->dim) {
    actx->size[2] = AIR_UINT(oversample*nten->axis[3].size);
  } else {
    actx->size[2] = 1;
  }

  return 0;
}
Example #4
0
/*
** max length of line formatted "[<key>] <err>\n"
*/
unsigned int
biffMsgLineLenMax(const biffMsg *msg) {
  unsigned int ii, len, maxlen;

  if (biffMsgNoop == msg) {
    return 0;
  }
  maxlen = 0;
  for (ii=0; ii<msg->errNum; ii++) {
    len = AIR_UINT(strlen(msg->err[ii]) + strlen(msg->key) + strlen("[] \n"));
    maxlen = AIR_MAX(maxlen, len);
  }
  return maxlen;
}
Example #5
0
/*
** _airEnumIndex()
**
** given an enum "enm" and value "val", return the index into enm->str[]
** and enm->desc[] which correspond to that value.  To be safe, when
** given an invalid enum value, we return zero.
*/
static unsigned int
_airEnumIndex(const airEnum *enm, int val) {
  unsigned int ii, ret;

  ret = 0;
  if (enm->val) {
    for (ii=1; ii<=enm->M; ii++) {
      if (val == enm->val[ii]) {
        ret = ii;
        break;
      }
    }
  } else {
    unsigned int uval;
    uval = AIR_UINT(val);
    ret = (0 <= val && uval <= enm->M) ? uval : 0;
  }
  return ret;
}
Example #6
0
/*
******** biffMsgStrlen
**
** returns length of string (not including null termination, as usual)
** of the error message that will be generated by biffMsgStrSet
*/
unsigned int
biffMsgStrlen(const biffMsg *msg) {
  static const char me[]="biffMsgStrlen";
  unsigned int ii, len;

  if (biffMsgNoop == msg) {
    return 0;
  }
  if (!( msg )) {
    fprintf(stderr, "%s: PANIC got NULL msg %p\n", me, AIR_CVOIDP(msg));
    return 0; /* exit(1); */
  }

  len = 0;
  for (ii=0; ii<msg->errNum; ii++) {
    len += AIR_UINT(strlen(msg->key)
                    + strlen(msg->err[ii]) + strlen("[] \n"));
  }
  return len+1;
}
Example #7
0
/*
** as of Sept 2013 this returns information: the index of the
** option just added.  Returns UINT_MAX in case of error.
*/
unsigned int
hestOptAdd(hestOpt **optP,
           const char *flag, const char *name,
           int type, int min, int max,
           void *valueP, const char *dflt, const char *info, ...) {
  hestOpt *ret = NULL;
  int num;
  va_list ap;
  unsigned int retIdx;

  if (!optP)
    return UINT_MAX;

  num = *optP ? _hestNumOpts(*optP) : 0;
  if (!( ret = AIR_CALLOC(num+2, hestOpt) )) {
    return UINT_MAX;
  }
  if (num)
    memcpy(ret, *optP, num*sizeof(hestOpt));
  retIdx = AIR_UINT(num);
  ret[num].flag = airStrdup(flag);
  ret[num].name = airStrdup(name);
  ret[num].type = type;
  ret[num].min = min;
  ret[num].max = max;
  ret[num].valueP = valueP;
  ret[num].dflt = airStrdup(dflt);
  ret[num].info = airStrdup(info);
  /* initialize the things that may be set below */
  ret[num].sawP = NULL;
  ret[num].enm = NULL;
  ret[num].CB = NULL;
  /* seems to be redundant with above _hestOptInit() */
  ret[num].source = hestSourceUnknown;
  /* deal with var args */
  if (5 == _hestKind(&(ret[num]))) {
    va_start(ap, info);
    ret[num].sawP = va_arg(ap, unsigned int*);
    va_end(ap);
  }
Example #8
0
/*
** assign random signs to the vectors and measures the length of their
** mean, as quickly as possible
*/
static double
party(Nrrd *npos, airRandMTState *rstate) {
  double *pos, mean[3];
  unsigned int ii, num, rnd, rndBit;

  pos = (double *)(npos->data);
  num = AIR_UINT(npos->axis[1].size);
  rnd = airUIrandMT_r(rstate);
  rndBit = 0;
  ELL_3V_SET(mean, 0, 0, 0);
  for (ii=0; ii<num; ii++) {
    if (32 == rndBit) {
      rnd = airUIrandMT_r(rstate);
      rndBit = 0;
    }
    if (rnd & (1 << rndBit++)) {
      ELL_3V_SCALE(pos + 3*ii, -1, pos + 3*ii);
    }
    ELL_3V_INCR(mean, pos + 3*ii);
  }
  ELL_3V_SCALE(mean, 1.0/num, mean);
  return ELL_3V_LEN(mean);
}
Example #9
0
int
tenGlyphGen(limnObject *glyphsLimn, echoScene *glyphsEcho,
            tenGlyphParm *parm,
            const Nrrd *nten, const Nrrd *npos, const Nrrd *nslc) {
  static const char me[]="tenGlyphGen";
  gageShape *shape;
  airArray *mop;
  float *tdata, eval[3], evec[9], *cvec, rotEvec[9], mA_f[16],
    absEval[3], glyphScl[3];
  double pI[3], pW[3], cl, cp, sRot[16], mA[16], mB[16], msFr[9], tmpvec[3],
    R, G, B, qA, qB, qC, glyphAniso, sliceGray;
  unsigned int duh;
  int slcCoord[3], idx, glyphIdx, axis, numGlyphs,
    svRGBAfl=AIR_FALSE;
  limnLook *look; int lookIdx;
  echoObject *eglyph, *inst, *list=NULL, *split, *esquare;
  echoPos_t eM[16], originOffset[3], edge0[3], edge1[3];
  char stmp[AIR_STRLEN_SMALL];
  /*
  int eret;
  double tmp1[3], tmp2[3];
  */

  if (!( (glyphsLimn || glyphsEcho) && nten && parm)) {
    biffAddf(TEN, "%s: got NULL pointer", me);
    return 1;
  }
  mop = airMopNew();
  shape = gageShapeNew();
  shape->defaultCenter = nrrdCenterCell;
  airMopAdd(mop, shape, (airMopper)gageShapeNix, airMopAlways);
  if (npos) {
    if (!( 2 == nten->dim && 7 == nten->axis[0].size )) {
      biffAddf(TEN, "%s: nten isn't 2-D 7-by-N array", me);
      airMopError(mop); return 1;
    }
    if (!( 2 == npos->dim && 3 == npos->axis[0].size
           && nten->axis[1].size == npos->axis[1].size )) {
      biffAddf(TEN, "%s: npos isn't 2-D 3-by-%s array", me,
               airSprintSize_t(stmp, nten->axis[1].size));
      airMopError(mop); return 1;
    }
    if (!( nrrdTypeFloat == nten->type && nrrdTypeFloat == npos->type )) {
      biffAddf(TEN, "%s: nten and npos must be %s, not %s and %s", me,
               airEnumStr(nrrdType, nrrdTypeFloat),
               airEnumStr(nrrdType, nten->type),
               airEnumStr(nrrdType, npos->type));
      airMopError(mop); return 1;
    }
  } else {
    if (tenTensorCheck(nten, nrrdTypeFloat, AIR_TRUE, AIR_TRUE)) {
      biffAddf(TEN, "%s: didn't get a valid DT volume", me);
      airMopError(mop); return 1;
    }
  }
  if (tenGlyphParmCheck(parm, nten, npos, nslc)) {
    biffAddf(TEN, "%s: trouble", me);
    airMopError(mop); return 1;
  }
  if (!npos) {
    if (gageShapeSet(shape, nten, tenGageKind->baseDim)) {
      biffMovef(TEN, GAGE, "%s: trouble", me);
      airMopError(mop); return 1;
    }
  }
  if (parm->doSlice) {
    ELL_3V_COPY(edge0, shape->spacing);
    ELL_3V_COPY(edge1, shape->spacing);
    edge0[parm->sliceAxis] = edge1[parm->sliceAxis] = 0.0;
    switch(parm->sliceAxis) {
    case 0:
      edge0[1] = edge1[2] = 0;
      ELL_4M_ROTATE_Y_SET(sRot, AIR_PI/2);
      break;
    case 1:
      edge0[0] = edge1[2] = 0;
      ELL_4M_ROTATE_X_SET(sRot, AIR_PI/2);
      break;
    case 2: default:
      edge0[0] = edge1[1] = 0;
      ELL_4M_IDENTITY_SET(sRot);
      break;
    }
    ELL_3V_COPY(originOffset, shape->spacing);
    ELL_3V_SCALE(originOffset, -0.5, originOffset);
    originOffset[parm->sliceAxis] *= -2*parm->sliceOffset;
  }
  if (glyphsLimn) {
    /* create limnLooks for diffuse and ambient-only shading */
    /* ??? */
    /* hack: save old value of setVertexRGBAFromLook, and set to true */
    svRGBAfl = glyphsLimn->setVertexRGBAFromLook;
    glyphsLimn->setVertexRGBAFromLook = AIR_TRUE;
  }
  if (glyphsEcho) {
    list = echoObjectNew(glyphsEcho, echoTypeList);
  }
  if (npos) {
    numGlyphs = AIR_UINT(nten->axis[1].size);
  } else {
    numGlyphs = shape->size[0] * shape->size[1] * shape->size[2];
  }
  /* find measurement frame transform */
  if (3 == nten->spaceDim
      && AIR_EXISTS(nten->measurementFrame[0][0])) {
    /*     msFr        nten->measurementFrame
    **   0  1  2      [0][0]   [1][0]   [2][0]
    **   3  4  5      [0][1]   [1][1]   [2][1]
    **   6  7  8      [0][2]   [1][2]   [2][2]
    */
    msFr[0] = nten->measurementFrame[0][0];
    msFr[3] = nten->measurementFrame[0][1];
    msFr[6] = nten->measurementFrame[0][2];
    msFr[1] = nten->measurementFrame[1][0];
    msFr[4] = nten->measurementFrame[1][1];
    msFr[7] = nten->measurementFrame[1][2];
    msFr[2] = nten->measurementFrame[2][0];
    msFr[5] = nten->measurementFrame[2][1];
    msFr[8] = nten->measurementFrame[2][2];
  } else {
    ELL_3M_IDENTITY_SET(msFr);
  }
  for (idx=0; idx<numGlyphs; idx++) {
    tdata = (float*)(nten->data) + 7*idx;
    if (parm->verbose >= 2) {
      fprintf(stderr, "%s: glyph %d/%d: hello %g    %g %g %g %g %g %g\n",
              me, idx, numGlyphs, tdata[0],
              tdata[1], tdata[2], tdata[3],
              tdata[4], tdata[5], tdata[6]);
    }
    if (!( TEN_T_EXISTS(tdata) )) {
      /* there's nothing we can do here */
      if (parm->verbose >= 2) {
        fprintf(stderr, "%s: glyph %d/%d: non-existent data\n",
                me, idx, numGlyphs);
      }
      continue;
    }
    if (npos) {
      ELL_3V_COPY(pW, (float*)(npos->data) + 3*idx);
      if (!( AIR_EXISTS(pW[0]) && AIR_EXISTS(pW[1]) && AIR_EXISTS(pW[2]) )) {
        /* position doesn't exist- perhaps because its from the push
           library, which might kill points by setting coords to nan */
        continue;
      }
    } else {
      NRRD_COORD_GEN(pI, shape->size, 3, idx);
      /* this does take into account full orientation */
      gageShapeItoW(shape, pW, pI);
      if (parm->nmask) {
        if (!( nrrdFLookup[parm->nmask->type](parm->nmask->data, idx)
               >= parm->maskThresh )) {
          if (parm->verbose >= 2) {
            fprintf(stderr, "%s: glyph %d/%d: doesn't meet mask thresh\n",
                    me, idx, numGlyphs);
          }
          continue;
        }
      }
    }
    tenEigensolve_f(eval, evec, tdata);
    /* transform eigenvectors by measurement frame */
    ELL_3MV_MUL(tmpvec, msFr, evec + 0);
    ELL_3V_COPY_TT(evec + 0, float, tmpvec);
    ELL_3MV_MUL(tmpvec, msFr, evec + 3);
    ELL_3V_COPY_TT(evec + 3, float, tmpvec);
    ELL_3MV_MUL(tmpvec, msFr, evec + 6);
    ELL_3V_COPY_TT(evec + 6, float, tmpvec);
    ELL_3V_CROSS(tmpvec, evec + 0, evec + 3);
    if (0 > ELL_3V_DOT(tmpvec, evec + 6)) {
      ELL_3V_SCALE(evec + 6, -1, evec + 6);
    }
    ELL_3M_TRANSPOSE(rotEvec, evec);
    if (parm->doSlice
        && pI[parm->sliceAxis] == parm->slicePos) {
      /* set sliceGray */
      if (nslc) {
        /* we aren't masked by confidence, as anisotropy slice is */
        for (duh=0; duh<parm->sliceAxis; duh++) {
          slcCoord[duh] = (int)(pI[duh]);
        }
        for (duh=duh<parm->sliceAxis; duh<2; duh++) {
          slcCoord[duh] = (int)(pI[duh+1]);
        }
        /* HEY: GLK has no idea what's going here */
        slcCoord[0] = (int)(pI[0]);
        slcCoord[1] = (int)(pI[1]);
        slcCoord[2] = (int)(pI[2]);
        sliceGray =
          nrrdFLookup[nslc->type](nslc->data, slcCoord[0]
                                  + nslc->axis[0].size*slcCoord[1]);
      } else {
        if (!( tdata[0] >= parm->confThresh )) {
          if (parm->verbose >= 2) {
            fprintf(stderr, "%s: glyph %d/%d (slice): conf %g < thresh %g\n",
                    me, idx, numGlyphs, tdata[0], parm->confThresh);
          }
          continue;
        }
        sliceGray = tenAnisoEval_f(eval, parm->sliceAnisoType);
      }
      if (parm->sliceGamma > 0) {
        sliceGray = AIR_AFFINE(0, sliceGray, 1, parm->sliceBias, 1);
        sliceGray = pow(sliceGray, 1.0/parm->sliceGamma);
      } else {
        sliceGray = AIR_AFFINE(0, sliceGray, 1, 0, 1-parm->sliceBias);
        sliceGray = 1.0 - pow(sliceGray, -1.0/parm->sliceGamma);
      }
      /* make slice contribution */
      /* HEY: this is *NOT* aware of shape->fromOrientation */
      if (glyphsLimn) {
        lookIdx = limnObjectLookAdd(glyphsLimn);
        look = glyphsLimn->look + lookIdx;
        ELL_4V_SET_TT(look->rgba, float, sliceGray, sliceGray, sliceGray, 1);
        ELL_3V_SET(look->kads, 1, 0, 0);
        look->spow = 0;
        glyphIdx = limnObjectSquareAdd(glyphsLimn, lookIdx);
        ELL_4M_IDENTITY_SET(mA);
        ell_4m_post_mul_d(mA, sRot);
        if (!npos) {
          ELL_4M_SCALE_SET(mB,
                           shape->spacing[0],
                           shape->spacing[1],
                           shape->spacing[2]);
        }
        ell_4m_post_mul_d(mA, mB);
        ELL_4M_TRANSLATE_SET(mB, pW[0], pW[1], pW[2]);
        ell_4m_post_mul_d(mA, mB);
        ELL_4M_TRANSLATE_SET(mB,
                             originOffset[0],
                             originOffset[1],
                             originOffset[2]);
        ell_4m_post_mul_d(mA, mB);
        ELL_4M_COPY_TT(mA_f, float, mA);
        limnObjectPartTransform(glyphsLimn, glyphIdx, mA_f);
      }
      if (glyphsEcho) {
        esquare = echoObjectNew(glyphsEcho,echoTypeRectangle);
        ELL_3V_ADD2(((echoRectangle*)esquare)->origin, pW, originOffset);
        ELL_3V_COPY(((echoRectangle*)esquare)->edge0, edge0);
        ELL_3V_COPY(((echoRectangle*)esquare)->edge1, edge1);
        echoColorSet(esquare,
                     AIR_CAST(echoCol_t, sliceGray),
                     AIR_CAST(echoCol_t, sliceGray),
                     AIR_CAST(echoCol_t, sliceGray), 1);
        /* this is pretty arbitrary- but I want shadows to have some effect.
           Previously, the material was all ambient: (A,D,S) = (1,0,0),
           which avoided all shadow effects. */
        echoMatterPhongSet(glyphsEcho, esquare, 0.4f, 0.6f, 0, 40);
        echoListAdd(list, esquare);
      }
    }
    if (parm->onlyPositive) {
      if (eval[2] < 0) {
        /* didn't have all positive eigenvalues, its outta here */
        if (parm->verbose >= 2) {
          fprintf(stderr, "%s: glyph %d/%d: not all evals %g %g %g > 0\n",
                  me, idx, numGlyphs, eval[0], eval[1], eval[2]);
        }
        continue;
      }
    }
    if (!( tdata[0] >= parm->confThresh )) {
      if (parm->verbose >= 2) {
        fprintf(stderr, "%s: glyph %d/%d: conf %g < thresh %g\n",
                me, idx, numGlyphs, tdata[0], parm->confThresh);
      }
      continue;
    }
    if (!( tenAnisoEval_f(eval, parm->anisoType) >= parm->anisoThresh )) {
      if (parm->verbose >= 2) {
        fprintf(stderr, "%s: glyph %d/%d: aniso[%d] %g < thresh %g\n",
                me, idx, numGlyphs, parm->anisoType,
                tenAnisoEval_f(eval, parm->anisoType), parm->anisoThresh);
      }
      continue;
    }
    glyphAniso = tenAnisoEval_f(eval, parm->colAnisoType);
    /*
      fprintf(stderr, "%s: eret = %d; evals = %g %g %g\n", me,
      eret, eval[0], eval[1], eval[2]);
      ELL_3V_CROSS(tmp1, evec+0, evec+3); tmp2[0] = ELL_3V_LEN(tmp1);
      ELL_3V_CROSS(tmp1, evec+0, evec+6); tmp2[1] = ELL_3V_LEN(tmp1);
      ELL_3V_CROSS(tmp1, evec+3, evec+6); tmp2[2] = ELL_3V_LEN(tmp1);
      fprintf(stderr, "%s: crosses = %g %g %g\n", me,
      tmp2[0], tmp2[1], tmp2[2]);
    */

    /* set transform (in mA) */
    ELL_3V_ABS(absEval, eval);
    ELL_4M_IDENTITY_SET(mA);                        /* reset */
    ELL_3V_SCALE(glyphScl, parm->glyphScale, absEval); /* scale by evals */
    ELL_4M_SCALE_SET(mB, glyphScl[0], glyphScl[1], glyphScl[2]);

    ell_4m_post_mul_d(mA, mB);
    ELL_43M_INSET(mB, rotEvec);                     /* rotate by evecs */
    ell_4m_post_mul_d(mA, mB);
    ELL_4M_TRANSLATE_SET(mB, pW[0], pW[1], pW[2]);  /* translate */
    ell_4m_post_mul_d(mA, mB);

    /* set color (in R,G,B) */
    cvec = evec + 3*(AIR_CLAMP(0, parm->colEvec, 2));
    R = AIR_ABS(cvec[0]);                           /* standard mapping */
    G = AIR_ABS(cvec[1]);
    B = AIR_ABS(cvec[2]);
    /* desaturate by colMaxSat */
    R = AIR_AFFINE(0.0, parm->colMaxSat, 1.0, parm->colIsoGray, R);
    G = AIR_AFFINE(0.0, parm->colMaxSat, 1.0, parm->colIsoGray, G);
    B = AIR_AFFINE(0.0, parm->colMaxSat, 1.0, parm->colIsoGray, B);
    /* desaturate some by anisotropy */
    R = AIR_AFFINE(0.0, parm->colAnisoModulate, 1.0,
                   R, AIR_AFFINE(0.0, glyphAniso, 1.0, parm->colIsoGray, R));
    G = AIR_AFFINE(0.0, parm->colAnisoModulate, 1.0,
                   G, AIR_AFFINE(0.0, glyphAniso, 1.0, parm->colIsoGray, G));
    B = AIR_AFFINE(0.0, parm->colAnisoModulate, 1.0,
                   B, AIR_AFFINE(0.0, glyphAniso, 1.0, parm->colIsoGray, B));
    /* clamp and do gamma */
    R = AIR_CLAMP(0.0, R, 1.0);
    G = AIR_CLAMP(0.0, G, 1.0);
    B = AIR_CLAMP(0.0, B, 1.0);
    R = pow(R, parm->colGamma);
    G = pow(G, parm->colGamma);
    B = pow(B, parm->colGamma);

    /* find axis, and superquad exponents qA and qB */
    if (eval[2] > 0) {
      /* all evals positive */
      cl = AIR_MIN(0.99, tenAnisoEval_f(eval, tenAniso_Cl1));
      cp = AIR_MIN(0.99, tenAnisoEval_f(eval, tenAniso_Cp1));
      if (cl > cp) {
        axis = 0;
        qA = pow(1-cp, parm->sqdSharp);
        qB = pow(1-cl, parm->sqdSharp);
      } else {
        axis = 2;
        qA = pow(1-cl, parm->sqdSharp);
        qB = pow(1-cp, parm->sqdSharp);
      }
      qC = qB;
    } else if (eval[0] < 0) {
      /* all evals negative */
      float aef[3];
      aef[0] = absEval[2];
      aef[1] = absEval[1];
      aef[2] = absEval[0];
      cl = AIR_MIN(0.99, tenAnisoEval_f(aef, tenAniso_Cl1));
      cp = AIR_MIN(0.99, tenAnisoEval_f(aef, tenAniso_Cp1));
      if (cl > cp) {
        axis = 2;
        qA = pow(1-cp, parm->sqdSharp);
        qB = pow(1-cl, parm->sqdSharp);
      } else {
        axis = 0;
        qA = pow(1-cl, parm->sqdSharp);
        qB = pow(1-cp, parm->sqdSharp);
      }
      qC = qB;
    } else {
#define OOSQRT2 0.70710678118654752440
#define OOSQRT3 0.57735026918962576451
      /* double poleA[3]={OOSQRT3, OOSQRT3, OOSQRT3}; */
      double poleB[3]={1, 0, 0};
      double poleC[3]={OOSQRT2, OOSQRT2, 0};
      double poleD[3]={OOSQRT3, -OOSQRT3, -OOSQRT3};
      double poleE[3]={OOSQRT2, 0, -OOSQRT2};
      double poleF[3]={OOSQRT3, OOSQRT3, -OOSQRT3};
      double poleG[3]={0, -OOSQRT2, -OOSQRT2};
      double poleH[3]={0, 0, -1};
      /* double poleI[3]={-OOSQRT3, -OOSQRT3, -OOSQRT3}; */
      double funk[3]={0,4,2}, thrn[3]={1,4,4};
      double octa[3]={0,2,2}, cone[3]={1,2,2};
      double evalN[3], tmp, bary[3];
      double qq[3];

      ELL_3V_NORM(evalN, eval, tmp);
      if (eval[1] >= -eval[2]) {
        /* inside B-F-C */
        ell_3v_barycentric_spherical_d(bary, poleB, poleF, poleC, evalN);
        ELL_3V_SCALE_ADD3(qq, bary[0], octa, bary[1], thrn, bary[2], cone);
        axis = 2;
      } else if (eval[0] >= -eval[2]) {
        /* inside B-D-F */
        if (eval[1] >= 0) {
          /* inside B-E-F */
          ell_3v_barycentric_spherical_d(bary, poleB, poleE, poleF, evalN);
          ELL_3V_SCALE_ADD3(qq, bary[0], octa, bary[1], funk, bary[2], thrn);
          axis = 2;
        } else {
          /* inside B-D-E */
          ell_3v_barycentric_spherical_d(bary, poleB, poleD, poleE, evalN);
          ELL_3V_SCALE_ADD3(qq, bary[0], cone, bary[1], thrn, bary[2], funk);
          axis = 0;
        }
      } else if (eval[0] < -eval[1]) {
        /* inside D-G-H */
        ell_3v_barycentric_spherical_d(bary, poleD, poleG, poleH, evalN);
        ELL_3V_SCALE_ADD3(qq, bary[0], thrn, bary[1], cone, bary[2], octa);
        axis = 0;
      } else if (eval[1] < 0) {
        /* inside E-D-H */
        ell_3v_barycentric_spherical_d(bary, poleE, poleD, poleH, evalN);
        ELL_3V_SCALE_ADD3(qq, bary[0], funk, bary[1], thrn, bary[2], octa);
        axis = 0;
      } else {
        /* inside F-E-H */
        ell_3v_barycentric_spherical_d(bary, poleF, poleE, poleH, evalN);
        ELL_3V_SCALE_ADD3(qq, bary[0], thrn, bary[1], funk, bary[2], cone);
        axis = 2;
      }
      qA = qq[0];
      qB = qq[1];
      qC = qq[2];
#undef OOSQRT2
#undef OOSQRT3
    }

    /* add the glyph */
    if (parm->verbose >= 2) {
      fprintf(stderr, "%s: glyph %d/%d: the glyph stays!\n",
              me, idx, numGlyphs);
    }
    if (glyphsLimn) {
      lookIdx = limnObjectLookAdd(glyphsLimn);
      look = glyphsLimn->look + lookIdx;
      ELL_4V_SET_TT(look->rgba, float, R, G, B, 1);
      ELL_3V_SET(look->kads, parm->ADSP[0], parm->ADSP[1], parm->ADSP[2]);
      look->spow = 0;
      switch(parm->glyphType) {
      case tenGlyphTypeBox:
        glyphIdx = limnObjectCubeAdd(glyphsLimn, lookIdx);
        break;
      case tenGlyphTypeSphere:
        glyphIdx = limnObjectPolarSphereAdd(glyphsLimn, lookIdx, axis,
                                            2*parm->facetRes, parm->facetRes);
        break;
      case tenGlyphTypeCylinder:
        glyphIdx = limnObjectCylinderAdd(glyphsLimn, lookIdx, axis,
                                         parm->facetRes);
        break;
      case tenGlyphTypeSuperquad:
      default:
        glyphIdx =
          limnObjectPolarSuperquadFancyAdd(glyphsLimn, lookIdx, axis,
                                           AIR_CAST(float, qA),
                                           AIR_CAST(float, qB),
                                           AIR_CAST(float, qC), 0,
                                           2*parm->facetRes,
                                           parm->facetRes);
        break;
      }
      ELL_4M_COPY_TT(mA_f, float, mA);
      limnObjectPartTransform(glyphsLimn, glyphIdx, mA_f);
    }
    if (glyphsEcho) {
      switch(parm->glyphType) {
      case tenGlyphTypeBox:
        eglyph = echoObjectNew(glyphsEcho, echoTypeCube);
        /* nothing else to set */
        break;
      case tenGlyphTypeSphere:
        eglyph = echoObjectNew(glyphsEcho, echoTypeSphere);
        echoSphereSet(eglyph, 0, 0, 0, 1);
        break;
      case tenGlyphTypeCylinder:
        eglyph = echoObjectNew(glyphsEcho, echoTypeCylinder);
        echoCylinderSet(eglyph, axis);
        break;
      case tenGlyphTypeSuperquad:
      default:
        eglyph = echoObjectNew(glyphsEcho, echoTypeSuperquad);
        echoSuperquadSet(eglyph, axis, qA, qB);
        break;
      }
      echoColorSet(eglyph,
                   AIR_CAST(echoCol_t, R),
                   AIR_CAST(echoCol_t, G),
                   AIR_CAST(echoCol_t, B), 1);
      echoMatterPhongSet(glyphsEcho, eglyph,
                         parm->ADSP[0], parm->ADSP[1],
                         parm->ADSP[2], parm->ADSP[3]);
      inst = echoObjectNew(glyphsEcho, echoTypeInstance);
      ELL_4M_COPY(eM, mA);
      echoInstanceSet(inst, eM, eglyph);
      echoListAdd(list, inst);
    }
  }
  if (glyphsLimn) {
    glyphsLimn->setVertexRGBAFromLook = svRGBAfl;
  }
  if (glyphsEcho) {
    split = echoListSplit3(glyphsEcho, list, 10);
    echoObjectAdd(glyphsEcho, split);
  }

  airMopOkay(mop);
  return 0;
}
Example #10
0
/*
******** tenGradientDistribute
**
** Takes the given list of gradients, normalizes their lengths,
** optionally jitters their positions, does point repulsion, and then
** (optionally) selects a combination of directions with minimum vector sum.
**
** The complicated part of this is the point repulsion, which uses a
** gradient descent with variable set size. The progress of the system
** is measured by decrease in potential (when its measurement doesn't
** overflow to infinity) or an increase in the minimum angle.  When a
** step results in negative progress, the step size is halved, and the
** iteration is attempted again.  Based on the observation that at
** some points the step size must be made very small to get progress,
** the step size is cautiously increased ("nudged") at every
** iteration, to try to avoid using an overly small step.  The amount
** by which the step is nudged is halved everytime the step is halved,
** to avoid endless cycling through step sizes.
*/
int
tenGradientDistribute(Nrrd *nout, const Nrrd *nin,
                      tenGradientParm *tgparm) {
  static const char me[]="tenGradientDistribute";
  char filename[AIR_STRLEN_SMALL];
  unsigned int ii, num, iter, oldIdx, newIdx, edgeShrink;
  airArray *mop;
  Nrrd *npos[2];
  double *pos, len, meanVelocity, pot, potNew, potD,
    edge, edgeMin, angle, angleNew;
  int E;

  if (!nout || tenGradientCheck(nin, nrrdTypeUnknown, 2) || !tgparm) {
    biffAddf(TEN, "%s: got NULL pointer or invalid input", me);
    return 1;
  }

  num = AIR_UINT(nin->axis[1].size);
  mop = airMopNew();
  npos[0] = nrrdNew();
  npos[1] = nrrdNew();
  airMopAdd(mop, npos[0], (airMopper)nrrdNuke, airMopAlways);
  airMopAdd(mop, npos[1], (airMopper)nrrdNuke, airMopAlways);
  if (nrrdConvert(npos[0], nin, nrrdTypeDouble)
      || nrrdConvert(npos[1], nin, nrrdTypeDouble)) {
    biffMovef(TEN, NRRD, "%s: trouble allocating temp buffers", me);
    airMopError(mop); return 1;
  }

  pos = (double*)(npos[0]->data);
  for (ii=0; ii<num; ii++) {
    ELL_3V_NORM(pos, pos, len);
    pos += 3;
  }
  if (tgparm->jitter) {
    if (tenGradientJitter(npos[0], npos[0], tgparm->jitter)) {
      biffAddf(TEN, "%s: problem jittering input", me);
      airMopError(mop); return 1;
    }
  }

  /* initialize things prior to first iteration; have to
     make sure that loop body tests pass 1st time around */
  meanVelocity = 2*tgparm->minVelocity;
  potD = -2*tgparm->minPotentialChange;
  oldIdx = 0;
  newIdx = 1;
  tgparm->step = tgparm->initStep;
  tgparm->nudge = 0.1;
  tenGradientMeasure(&pot, &angle, NULL,
                     npos[oldIdx], tgparm, AIR_TRUE);
  for (iter = 0;
       ((!!tgparm->minIteration && iter < tgparm->minIteration)
        ||
        (iter < tgparm->maxIteration
         && (!tgparm->minPotentialChange
             || !AIR_EXISTS(potD)
             || -potD > tgparm->minPotentialChange)
         && (!tgparm->minVelocity
             || meanVelocity > tgparm->minVelocity)
         && tgparm->step > FLT_MIN));
       iter++) {
    /* copy positions from old to new */
    memcpy(npos[newIdx]->data, npos[oldIdx]->data, 3*num*sizeof(double));
    edge = tenGradientIdealEdge(num, tgparm->single);
    edgeShrink = 0;
    /* try to do a position update, which will fail if repulsion values
       explode, from having an insufficiently small edge normalization,
       so retry with smaller edge next time */
    do {
      E = _tenGradientUpdate(&meanVelocity, &edgeMin,
                             npos[newIdx], edge, tgparm);
      if (E) {
        if (edgeShrink > tgparm->maxEdgeShrink) {
          biffAddf(TEN, "%s: %u > %u edge shrinks (%g), update still failed",
                  me, edgeShrink, tgparm->maxEdgeShrink, edge);
          airMopError(mop); return 1;
        }
        edgeShrink++;
        /* re-initialize positions (HEY ugly code logic) */
        memcpy(npos[newIdx]->data, npos[oldIdx]->data, 3*num*sizeof(double));
        edge = edgeMin;
      }
    } while (E);
    tenGradientMeasure(&potNew, &angleNew, NULL,
                       npos[newIdx], tgparm, AIR_TRUE);
    if ((AIR_EXISTS(pot) && AIR_EXISTS(potNew) && potNew <= pot)
        || angleNew >= angle) {
      /* there was progress of some kind, either through potential
         decrease, or angle increase */
      potD = 2*(potNew - pot)/(potNew + pot);
      if (!(iter % tgparm->report) && tgparm->verbose) {
        fprintf(stderr, "%s(%d): . . . . . . step = %g, edgeShrink = %u\n"
                "   velo = %g<>%g, phi = %g ~ %g<>%g, angle = %g ~ %g\n",
                me, iter, tgparm->step, edgeShrink,
                meanVelocity, tgparm->minVelocity,
                pot, potD, tgparm->minPotentialChange,
                angle, angleNew - angle);
      }
      if (tgparm->snap && !(iter % tgparm->snap)) {
        sprintf(filename, "%05d.nrrd", iter/tgparm->snap);
        if (tgparm->verbose) {
          fprintf(stderr, "%s(%d): . . . . . . saving %s\n",
                  me, iter, filename);
        }
        if (nrrdSave(filename, npos[newIdx], NULL)) {
          char *serr;
          serr = biffGetDone(NRRD);
          if (tgparm->verbose) { /* perhaps shouldn't have this check */
            fprintf(stderr, "%s: iter=%d, couldn't save snapshot:\n%s"
                    "continuing ...\n", me, iter, serr);
          }
          free(serr);
        }
      }
      tgparm->step *= 1 + tgparm->nudge;
      tgparm->step = AIR_MIN(tgparm->initStep, tgparm->step);
      pot = potNew;
      angle = angleNew;
      /* swap buffers */
      newIdx = 1 - newIdx;
      oldIdx = 1 - oldIdx;
    } else {
      /* oops, did not make progress; back off and try again */
      if (tgparm->verbose) {
        fprintf(stderr, "%s(%d): ######## step %g --> %g\n"
                " phi = %g --> %g ~ %g, angle = %g --> %g\n",
                me, iter, tgparm->step, tgparm->step/2,
                pot, potNew, potD, angle, angleNew);
      }
      tgparm->step /= 2;
      tgparm->nudge /= 2;
    }
  }

  /* when the for-loop test fails, we stop before computing the next
     iteration (which starts with copying from npos[oldIdx] to
     npos[newIdx]) ==> the final results are in npos[oldIdx] */

  if (tgparm->verbose) {
    fprintf(stderr, "%s: .......................... done distribution:\n"
            "  (%d && %d) || (%d \n"
            "               && (%d || %d || %d) \n"
            "               && (%d || %d) \n"
            "               && %d) is false\n", me,
            !!tgparm->minIteration, iter < tgparm->minIteration,
            iter < tgparm->maxIteration,
            !tgparm->minPotentialChange,
            !AIR_EXISTS(potD), AIR_ABS(potD) > tgparm->minPotentialChange,
            !tgparm->minVelocity, meanVelocity > tgparm->minVelocity,
            tgparm->step > FLT_MIN);
    fprintf(stderr, "  iter=%d, velo = %g<>%g, phi = %g ~ %g<>%g;\n",
            iter, meanVelocity, tgparm->minVelocity, pot,
            potD, tgparm->minPotentialChange);
    fprintf(stderr, "  minEdge = %g; idealEdge = %g\n",
            2*sin(angle/2), tenGradientIdealEdge(num, tgparm->single));
  }

  tenGradientMeasure(&pot, NULL, NULL, npos[oldIdx], tgparm, AIR_FALSE);
  tgparm->potential = pot;
  tenGradientMeasure(&pot, &angle, &edge, npos[oldIdx], tgparm, AIR_TRUE);
  tgparm->potentialNorm = pot;
  tgparm->angle = angle;
  tgparm->edge = edge;
  tgparm->itersUsed = iter;

  if ((tgparm->minMeanImprovement || tgparm->minMean)
      && !tgparm->single) {
    if (tgparm->verbose) {
      fprintf(stderr, "%s: optimizing balance:\n", me);
    }
    if (tenGradientBalance(nout, npos[oldIdx], tgparm)) {
      biffAddf(TEN, "%s: failed to minimize vector sum of gradients", me);
      airMopError(mop); return 1;
    }
    if (tgparm->verbose) {
      fprintf(stderr, "%s: .......................... done balancing.\n", me);
    }
  } else {
    if (tgparm->verbose) {
      fprintf(stderr, "%s: .......................... (no balancing)\n", me);
    }
    if (nrrdConvert(nout, npos[oldIdx], nrrdTypeDouble)) {
      biffMovef(TEN, NRRD, "%s: couldn't set output", me);
      airMopError(mop); return 1;
    }
  }

  airMopOkay(mop);
  return 0;
}
Example #11
0
/*
** Do asynchronous update of positions in "npos', based on force
** calculations wherein the distances are normalized "edge".  Using a
** small "edge" allows forces to either underflow to zero, or be
** finite, instead of exploding to infinity, for high exponents.
**
** The smallest seen edge length is recorded in "*edgeMin", which is
** initialized to the given "edge".  This allows, for example, the
** caller to try again with a smaller edge normalization.
**
** The mean velocity of the points through the update is recorded in
** "*meanVel".
**
** Based on the observation that when using large exponents, numerical
** difficulties arise from the (force-based) update of the positions
** of the two (or few) closest particles, this function puts a speed
** limit (variable "limit") on the distance a particle may move during
** update, expressed as a fraction of the normalizing edge length.
** "limit" has been set heuristically, according to the exponent (we
** have to clamp speeds more aggresively with higher exponents), as
** well as (even more heuristically) according to the number of times
** the step size has been decreased.  This latter factor has to be
** bounded, so that the update is not unnecessarily bounded when the
** step size gets very small at the last stages of computation.
** Without the step-size-based speed limit, the step size would
** sometimes (e.g. num=200, expo=300) have to reduced to a miniscule
** value, which slows subsequent convergence terribly.
**
** this function is not static, though it could be, so that mac's
** "Sampler" app can profile this
*/
int
_tenGradientUpdate(double *meanVel, double *edgeMin,
                   Nrrd *npos, double edge, tenGradientParm *tgparm) {
  /* static const char me[]="_tenGradientUpdate"; */
  double *pos, newpos[3], grad[3], ngrad[3],
    dir[3], len, rep, step, diff[3], limit, expo;
  int num, ii, jj, E;

  E = 0;
  pos = AIR_CAST(double *, npos->data);
  num = AIR_UINT(npos->axis[1].size);
  *meanVel = 0;
  *edgeMin = edge;
  expo = tgparm->expo ? tgparm->expo : tgparm->expo_d;
  limit = expo*AIR_MIN(sqrt(expo),
                       log(1 + tgparm->initStep/tgparm->step));
  for (ii=0; ii<num; ii++) {
    ELL_3V_SET(grad, 0, 0, 0);
    for (jj=0; jj<num; jj++) {
      if (ii == jj) {
        continue;
      }
      ELL_3V_SUB(dir, pos + 3*ii, pos + 3*jj);
      ELL_3V_NORM(dir, dir, len);
      *edgeMin = AIR_MIN(*edgeMin, len);
      if (tgparm->expo) {
        rep = airIntPow(edge/len, tgparm->expo+1);
      } else {
        rep = pow(edge/len, tgparm->expo_d+1);
      }
      ELL_3V_SCALE_INCR(grad, rep/num, dir);
      if (!tgparm->single) {
        ELL_3V_ADD2(dir, pos + 3*ii, pos + 3*jj);
        ELL_3V_NORM(dir, dir, len);
        *edgeMin = AIR_MIN(*edgeMin, len);
        if (tgparm->expo) {
          rep = airIntPow(edge/len, tgparm->expo+1);
        } else {
          rep = pow(edge/len, tgparm->expo_d+1);
        }
        ELL_3V_SCALE_INCR(grad, rep/num, dir);
      }
    }
    ELL_3V_NORM(ngrad, grad, len);
    if (!( AIR_EXISTS(len) )) {
      /* things blew up, either in incremental force
         additions, or in the attempt at normalization */
      E = 1;
      *meanVel = AIR_NAN;
      break;
    }
    if (0 == len) {
      /* if the length of grad[] underflowed to zero, we can
         legitimately zero out ngrad[] */
      ELL_3V_SET(ngrad, 0, 0, 0);
    }
    step = AIR_MIN(len*tgparm->step, edge/limit);
    ELL_3V_SCALE_ADD2(newpos,
                      1.0, pos + 3*ii,
                      step, ngrad);
    ELL_3V_NORM(newpos, newpos, len);
    ELL_3V_SUB(diff, pos + 3*ii, newpos);
    *meanVel += ELL_3V_LEN(diff);
    ELL_3V_COPY(pos + 3*ii, newpos);
  }
  *meanVel /= num;

  return E;
}
Example #12
0
void
tenGradientMeasure(double *pot, double *minAngle, double *minEdge,
                   const Nrrd *npos, tenGradientParm *tgparm,
                   int edgeNormalize) {
  /* static const char me[]="tenGradientMeasure"; */
  double diff[3], *pos, atmp=0, ptmp, edge, len;
  unsigned int ii, jj, num;

  /* allow minAngle NULL */
  if (!(pot && npos && tgparm )) {
    return;
  }

  num = AIR_UINT(npos->axis[1].size);
  pos = AIR_CAST(double *, npos->data);
  edge = (edgeNormalize
          ? tenGradientIdealEdge(num, tgparm->single)
          : 1.0);
  *pot = 0;
  if (minAngle) {
    *minAngle = AIR_PI;
  }
  if (minEdge) {
    *minEdge = 2;
  }
  for (ii=0; ii<num; ii++) {
    for (jj=0; jj<ii; jj++) {
      ELL_3V_SUB(diff, pos + 3*ii, pos + 3*jj);
      len = ELL_3V_LEN(diff);
      if (minEdge) {
        *minEdge = AIR_MIN(*minEdge, len);
      }
      if (tgparm->expo) {
        ptmp = airIntPow(edge/len, tgparm->expo);
      } else {
        ptmp = pow(edge/len, tgparm->expo_d);
      }
      *pot += ptmp;
      if (minAngle) {
        atmp = ell_3v_angle_d(pos + 3*ii, pos + 3*jj);
        *minAngle = AIR_MIN(atmp, *minAngle);
      }
      if (!tgparm->single) {
        *pot += ptmp;
        ELL_3V_ADD2(diff, pos + 3*ii, pos + 3*jj);
        len = ELL_3V_LEN(diff);
        if (minEdge) {
          *minEdge = AIR_MIN(*minEdge, len);
        }
        if (tgparm->expo) {
          *pot += 2*airIntPow(edge/len, tgparm->expo);
        } else {
          *pot += 2*pow(edge/len, tgparm->expo_d);
        }
        if (minAngle) {
          *minAngle = AIR_MIN(AIR_PI-atmp, *minAngle);
        }
      }
    }
  }
  return;
}
Example #13
0
/*
******** unrrduCmdMain
**
** A "main" function for unu-like programs, which is very similar to
** teem/src/bin/unu.c:main(), and
** teem/src/bin/tend.c:main(), and
** teem/src/limn/test/lpu.c:main().
** With more time (and a major Teem release), this function may change,
** and those programs may use this.
**
** A sneaky but basic issue is the const-correctness of how the hestParm
** is used; we'd like to take a const hestParm* to communicate parameters
** the caller has set, but the show-stopper is that unrrduCmd->main()
** takes a non-const hestParm, and it has to be that way, because some
** unu commands alter the given hparm (which probably shouldn't happen).
** Until that's fixed, we have a non-const hestParm* coming in here.
*/
int
unrrduCmdMain(int argc, const char **argv,
              const char *cmd, const char *title,
              const unrrduCmd *const *cmdList,
              hestParm *_hparm, FILE *fusage) {
  int i, ret;
  const char *me;
  char *argv0 = NULL;
  hestParm *hparm;
  airArray *mop;

  me = argv[0];

  /* parse environment variables first, in case they break nrrdDefault*
     or nrrdState* variables in a way that nrrdSanity() should see */
  nrrdDefaultGetenv();
  nrrdStateGetenv();

  /* unu does some unu-specific environment-variable handling here */

  nrrdSanityOrDie(me);

  mop = airMopNew();
  if (_hparm) {
    hparm = _hparm;
  } else {
    hparm = hestParmNew();
    airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways);
    hparm->elideSingleEnumType = AIR_TRUE;
    hparm->elideSingleOtherType = AIR_TRUE;
    hparm->elideSingleOtherDefault = AIR_FALSE;
    hparm->elideSingleNonExistFloatDefault = AIR_TRUE;
    hparm->elideMultipleNonExistFloatDefault = AIR_TRUE;
    hparm->elideSingleEmptyStringDefault = AIR_TRUE;
    hparm->elideMultipleEmptyStringDefault = AIR_TRUE;
    hparm->cleverPluralizeOtherY = AIR_TRUE;
    /* learning columns from current window; if ioctl is available
    if (1) {
      struct winsize ws;
      ioctl(1, TIOCGWINSZ, &ws);
      hparm->columns = ws.ws_col - 1;
    }
    */
    hparm->columns = 78;
  }

  /* if there are no arguments, then we give general usage information */
  if (1 >= argc) {
    /* this is like unrrduUsageUnu() */
    unsigned int ii, maxlen = 0;
    char *buff, *fmt, tdash[] = "--- %s ---";
    for (ii=0; cmdList[ii]; ii++) {
      if (cmdList[ii]->hidden) {
        continue;
      }
      maxlen = AIR_MAX(maxlen, AIR_UINT(strlen(cmdList[ii]->name)));
    }
    if (!maxlen) {
      fprintf(fusage, "%s: problem: maxlen = %u\n", me, maxlen);
      airMopError(mop); return 1;
    }
    buff = AIR_CALLOC(strlen(tdash) + strlen(title) + 1, char);
    airMopAdd(mop, buff, airFree, airMopAlways);
    sprintf(buff, tdash, title);
    fmt = AIR_CALLOC(hparm->columns + strlen(buff) + 1, char); /* generous */
    airMopAdd(mop, buff, airFree, airMopAlways);
    sprintf(fmt, "%%%us\n",
            AIR_UINT((hparm->columns-strlen(buff))/2 + strlen(buff) - 1));
    fprintf(fusage, fmt, buff);

    for (ii=0; cmdList[ii]; ii++) {
      unsigned int cc, len;
      if (cmdList[ii]->hidden) {
        continue;
      }
      len = AIR_UINT(strlen(cmdList[ii]->name));
      strcpy(buff, "");
      for (cc=len; cc<maxlen; cc++)
        strcat(buff, " ");
      strcat(buff, cmd);
      strcat(buff, " ");
      strcat(buff, cmdList[ii]->name);
      strcat(buff, " ... ");
      len = strlen(buff);
      fprintf(fusage, "%s", buff);
      _hestPrintStr(fusage, len, len, hparm->columns,
                    cmdList[ii]->info, AIR_FALSE);
    }
    airMopError(mop);
    return 1;
  }
Example #14
0
File: dice.c Project: BRAINSia/teem
int
unrrdu_diceMain(int argc, const char **argv, const char *me,
                hestParm *hparm) {
  hestOpt *opt = NULL;
  char *base, *err, fnout[AIR_STRLEN_MED], /* file name out */
    fffname[AIR_STRLEN_MED],  /* format for filename */
    *ftmpl;                   /* format template */
  Nrrd *nin, *nout;
  int pret, fit;
  unsigned int axis, start, pos, top, size, sanity;
  airArray *mop;

  OPT_ADD_AXIS(axis, "axis to slice along");
  OPT_ADD_NIN(nin, "input nrrd");
  hestOptAdd(&opt, "s,start", "start", airTypeUInt, 1, 1, &start, "0",
             "integer value to start numbering with");
  hestOptAdd(&opt, "ff,format", "form", airTypeString, 1, 1, &ftmpl, "",
             "a printf-style format to use for generating all "
             "filenames.  Use this to override the number of characters "
             "used to represent the slice position, or the file format "
             "of the output, e.g. \"-ff %03d.ppm\" for 000.ppm, "
             "001.ppm, etc. By default (not using this option), slices "
             "are saved in NRRD format (or PNM or PNG where possible) "
             "with shortest possible filenames.");
  /* the fact that we're using unsigned int instead of size_t is
     its own kind of sanity check */
  hestOptAdd(&opt, "l,limit", "max#", airTypeUInt, 1, 1, &sanity, "9999",
             "a sanity check on how many slice files should be saved "
             "out, to prevent accidentally dicing the wrong axis "
             "or the wrong array. Can raise this value if needed.");
  hestOptAdd(&opt, "o,output", "prefix", airTypeString, 1, 1, &base, NULL,
             "output filename prefix (excluding info set via \"-ff\"), "
             "basically to set path of output files (so be sure to end "
             "with \"/\".");

  mop = airMopNew();
  airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways);

  USAGE(_unrrdu_diceInfoL);
  PARSE();
  airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways);

  if (!( axis < nin->dim )) {
    fprintf(stderr, "%s: given axis (%u) outside range [0,%u]\n",
            me, axis, nin->dim-1);
    airMopError(mop);
    return 1;
  }
  if (nin->axis[axis].size > sanity) {
    char stmp[AIR_STRLEN_SMALL];
    fprintf(stderr, "%s: axis %u size %s > sanity limit %u; "
            "increase via \"-l\"\n", me,
            axis, airSprintSize_t(stmp, nin->axis[axis].size), sanity);
    airMopError(mop);
    return 1;
  }
  size = AIR_UINT(nin->axis[axis].size);

  /* HEY: this should use nrrdSaveMulti(), and if there's additional
     smarts here, they should be moved into nrrdSaveMulti() */
  if (airStrlen(ftmpl)) {
    if (!( _nrrdContainsPercentThisAndMore(ftmpl, 'd')
           || _nrrdContainsPercentThisAndMore(ftmpl, 'u') )) {
      fprintf(stderr, "%s: given filename format \"%s\" doesn't seem to "
              "have the converstion specification to print an integer\n",
              me, ftmpl);
      airMopError(mop);
      return 1;
    }
    sprintf(fffname, "%%s%s", ftmpl);
  } else {
    unsigned int dignum=0, tmps;
    tmps = top = start + size - 1;
    do {
      dignum++;
      tmps /= 10;
    } while (tmps);
    /* sprintf the number of digits into the string that will be used
       to sprintf the slice number into the filename */
    sprintf(fffname, "%%s%%0%uu.nrrd", dignum);
  }
  nout = nrrdNew();
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);

  for (pos=0; pos<size; pos++) {
    if (nrrdSlice(nout, nin, axis, pos)) {
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: error slicing nrrd:%s\n", me, err);
      airMopError(mop);
      return 1;
    }
    if (0 == pos && !airStrlen(ftmpl)) {
      /* See if these slices would be better saved as PNG or PNM images.
         Altering the file name will tell nrrdSave() to use a different
         file format.  We wait till now to check this so that we can
         work from the actual slice */
      if (nrrdFormatPNG->fitsInto(nout, nrrdEncodingRaw, AIR_FALSE)) {
        strcpy(fffname + strlen(fffname) - 4, "png");
      } else {
        fit = nrrdFormatPNM->fitsInto(nout, nrrdEncodingRaw, AIR_FALSE);
        if (2 == fit) {
          strcpy(fffname + strlen(fffname) - 4, "pgm");
        } else if (3 == fit) {
          strcpy(fffname + strlen(fffname) - 4, "ppm");
        }
      }
    }
    sprintf(fnout, fffname, base, pos+start);
    fprintf(stderr, "%s: %s ...\n", me, fnout);
    if (nrrdSave(fnout, nout, NULL)) {
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: error writing nrrd to \"%s\":%s\n",
              me, fnout, err);
      airMopError(mop);
      return 1;
    }
  }

  airMopOkay(mop);
  return 0;
}
Example #15
0
int
coilContextAllSet(coilContext *cctx, const Nrrd *nin,
                  const coilKind *kind, const coilMethod *method,
                  unsigned int radius, unsigned int numThreads, int verbose,
                  double parm[COIL_PARMS_NUM]) {
  static const char me[]="coilContextAllSet";
  int someExist, allExist, baseDim, pi;
  size_t size[NRRD_DIM_MAX], sx, sy, sz;
  double xsp, ysp, zsp;
  airArray *mop;

  cctx->verbose = verbose;
  if (!( cctx && nin && kind && method )) {
    biffAddf(COIL, "%s: got NULL pointer", me);
    return 1;
  }
  if (coilVolumeCheck(nin, kind)) {
    biffAddf(COIL, "%s: input volume not usable as %s", me, kind->name);
    return 1;
  }
  if (!( radius >= 1 && numThreads >= 1 )) {
    biffAddf(COIL, "%s: radius (%d) not >= 1 or numThreads (%d) not >= 1", me,
             radius, numThreads);
    return 1;
  }
  if (!( AIR_IN_OP(coilMethodTypeUnknown, method->type,
                   coilMethodTypeLast) )) {
    biffAddf(COIL, "%s: method->type %d not valid", me, method->type);
    return 1;
  }

  if (!kind->filter[method->type]) {
    biffAddf(COIL, "%s: sorry, %s filtering not available on %s kind",
             me, method->name, kind->name);
    return 1;
  }

  /* warn if we can't do the multiple threads user wants */
  if (numThreads > 1 && !airThreadCapable && airThreadNoopWarning) {
    fprintf(stderr, "%s: WARNING: this Teem not thread capable: using 1 "
            "thread, not %d\n", me, numThreads);
    numThreads = 1;
  }

  mop = airMopNew();

  /* set parms */
  for (pi=0; pi<method->numParm; pi++) {
    if (!AIR_EXISTS(parm[pi])) {
      biffAddf(COIL, "%s: parm[%d] (need %d) doesn't exist",
               me, pi, method->numParm);
      airMopError(mop); return 1;
    }
    cctx->parm[pi] = parm[pi];
  }

  /* set sizes and spacings */
  baseDim = (1 == kind->valLen ? 0 : 1);
  sx = nin->axis[0 + baseDim].size;
  sy = nin->axis[1 + baseDim].size;
  sz = nin->axis[2 + baseDim].size;
  if (sz < numThreads) {
    char stmp[AIR_STRLEN_SMALL];
    airSprintSize_t(stmp, sz);
    fprintf(stderr, "%s: wanted %d threads but volume only has %s slices, "
            "using %s threads instead\n", me, numThreads, stmp, stmp);
    numThreads = AIR_UINT(sz);
  }
  ELL_3V_SET(cctx->size, sx, sy, sz);
  xsp = nin->axis[0 + baseDim].spacing;
  ysp = nin->axis[1 + baseDim].spacing;
  zsp = nin->axis[2 + baseDim].spacing;
  someExist = AIR_EXISTS(xsp) || AIR_EXISTS(ysp) || AIR_EXISTS(zsp);
  allExist = AIR_EXISTS(xsp) && AIR_EXISTS(ysp) && AIR_EXISTS(zsp);
  if (!( someExist )) {
    fprintf(stderr, "%s: WARNING: assuming unit spacing for all axes\n", me);
    xsp = 1;
    ysp = 1;
    zsp = 1;
  } else {
    if ( !allExist ) {
      biffAddf(COIL, "%s: spacings (%g,%g,%g) not uniformly existent",
               me, xsp, ysp, zsp);
      airMopError(mop); return 1;
    }
  }
  ELL_3V_SET(cctx->spacing, xsp, ysp, zsp);
  if (cctx->verbose) {
    fprintf(stderr, "%s: spacings: %g %g %g\n", me,
            cctx->spacing[0], cctx->spacing[1], cctx->spacing[2]);
  }

  /* allocate nvol */
  if (0 == baseDim) {
    ELL_4V_SET(size, 2, sx, sy, sz);
  } else {
    ELL_5V_SET(size, kind->valLen, 2, sx, sy, sz);
  }
  cctx->nvol = nrrdNew();
  if (nrrdMaybeAlloc_nva(cctx->nvol, coil_nrrdType, 4 + baseDim, size)) {
    biffMovef(COIL, NRRD,
              "%s: couldn't allocate internal processing volume", me);
    airMopError(mop); return 1;
  }
  airMopAdd(mop, cctx->nvol, (airMopper)nrrdNuke, airMopOnError);

  cctx->nin = nin;
  cctx->kind = kind;
  cctx->method = method;
  cctx->radius = radius;
  cctx->numThreads = numThreads;

  airMopOkay(mop);
  return 0;
}