Example #1
0
void
nrrdRangeSafeSet(NrrdRange *range, const Nrrd *nrrd, int blind8BitRange) {
  double minIn, maxIn;

  if (!range) {
    return;
  }
  minIn = range->min;
  maxIn = range->max;
  nrrdRangeSet(range, nrrd, blind8BitRange);
  if (AIR_EXISTS(minIn)) {
    range->min = minIn;
  }
  if (AIR_EXISTS(maxIn)) {
    range->max = maxIn;
  }
  return;
}
Example #2
0
/*
** 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;
}
double
_nrrdApplyDomainMax(const Nrrd *nmap, int ramps, int mapAxis) {
  double ret;
  
  ret = nmap->axis[mapAxis].max;
  if (!AIR_EXISTS(ret)) {
    ret = nmap->axis[mapAxis].size;
    ret = ramps ? ret-1 : ret;
  }
  return ret;
}
Example #4
0
void
_nrrdMeasureHistoSum(void *ans, int ansType,
                     const void *line, int lineType, size_t len, 
                     double axmin, double axmax) {
  double sum, hits, val, (*lup)(const void*, size_t);
  size_t ii;
  
  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
    axmin = -0.5;
    axmax = len-0.5;
  }
  lup = nrrdDLookup[lineType];
  sum = 0;
  for (ii=0; ii<len; ii++) {
    val = NRRD_CELL_POS(axmin, axmax, len, ii);
    hits = lup(line, ii);
    hits = AIR_MAX(hits, 0);
    sum += hits*val;
  }
  nrrdDStore[ansType](ans, sum);
}
Example #5
0
int
pullScaleTracePlotAdd(pullContext *pctx, Nrrd *nwild, Nrrd *nccd,
                      Nrrd *nmask, double mth, airArray *insideArr,
                      double velHalf, pullTrace *pts) {
  static const char me[]="pullScaleTracePlotAdd";
  double ssr[2], *pos, *velo, *wild, *ccd, *mask;
  unsigned int pnum, pidx, sizeS, sizeV;

  if (!(pctx && nwild && nccd && pts)) {
    biffAddf(PULL, "%s: got NULL pointer", me);
    return 1;
  }
  if (!nrrdSameSize(nwild, nccd, AIR_TRUE)) {
    biffMovef(PULL, NRRD, "%s: nwild not same size as nccd", me);
    return 1;
  }
  if (nmask || insideArr) {
    if (!insideArr) {
      biffAddf(PULL, "%s: got nmask but not insideArr", me);
      return 1;
    }
    if (!nmask) {
      biffAddf(PULL, "%s: got insideArr but not nmask", me);
      return 1;
    }
    if (nrrdTypeDouble != nmask->type) {
      biffAddf(PULL, "%s: nmask has type %s but want %s", me,
               airEnumStr(nrrdType, nmask->type),
               airEnumStr(nrrdType, nrrdTypeDouble));
      return 1;
    }
    if (!nrrdSameSize(nwild, nmask, AIR_TRUE)) {
      biffMovef(PULL, NRRD, "%s: nwild not same size as nmask", me);
      return 1;
    }
    if (!nrrdSameSize(nccd, nmask, AIR_TRUE)) {
      biffMovef(PULL, NRRD, "%s: nccd not same size as nmask", me);
      return 1;
    }
    if (!AIR_EXISTS(mth)) {
      biffAddf(PULL, "%s: got non-existent mask thresh %g", me, mth);
      return 1;
    }
  }
  ssr[0] = nwild->axis[0].min;
  ssr[1] = nwild->axis[0].max;
  sizeS = AIR_CAST(unsigned int, nwild->axis[0].size);
  sizeV = AIR_CAST(unsigned int, nwild->axis[1].size);
  wild = AIR_CAST(double *, nwild->data);
  ccd = AIR_CAST(double *, nccd->data);
  if (nmask) {
    mask = AIR_CAST(double *, nmask->data);
  } else {
Example #6
0
/*
** _nrrdResampleCheckInfo()
**
** checks validity of given NrrdResampleInfo *info: 
** - all required parameters exist
** - both min[d] and max[d] for all axes d
*/
int
_nrrdResampleCheckInfo(const Nrrd *nin, const NrrdResampleInfo *info) {
  char me[] = "_nrrdResampleCheckInfo", err[BIFF_STRLEN];
  const NrrdKernel *k;
  int center, p, np;
  unsigned int ai, minsmp;

  if (nrrdTypeBlock == nin->type || nrrdTypeBlock == info->type) {
    sprintf(err, "%s: can't resample to or from type %s", me,
            airEnumStr(nrrdType, nrrdTypeBlock));
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdBoundaryUnknown == info->boundary) {
    sprintf(err, "%s: didn't set boundary behavior\n", me);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdBoundaryPad == info->boundary && !AIR_EXISTS(info->padValue)) {
    sprintf(err, "%s: asked for boundary padding, but no pad value set\n", me);
    biffAdd(NRRD, err); return 1;
  }
  for (ai=0; ai<nin->dim; ai++) {
    k = info->kernel[ai];
    /* we only care about the axes being resampled */
    if (!k)
      continue;
    if (!(info->samples[ai] > 0)) {
      sprintf(err, "%s: axis %d # samples (" _AIR_SIZE_T_CNV ") invalid", 
              me, ai, info->samples[ai]);
      biffAdd(NRRD, err); return 1;
    }
    if (!( AIR_EXISTS(nin->axis[ai].min) && AIR_EXISTS(nin->axis[ai].max) )) {
      sprintf(err, "%s: input nrrd's axis %d min,max have not both been set",
              me, ai);
      biffAdd(NRRD, err); return 1;
    }
    if (!( AIR_EXISTS(info->min[ai]) && AIR_EXISTS(info->max[ai]) )) {
      sprintf(err, "%s: info's axis %d min,max not both set", me, ai);
      biffAdd(NRRD, err); return 1;
    }
    np = k->numParm;
    for (p=0; p<np; p++) {
      if (!AIR_EXISTS(info->parm[ai][p])) {
        sprintf(err, "%s: didn't set parameter %d (of %d) for axis %d\n",
                me, p, np, ai);
        biffAdd(NRRD, err); return 1;
      }
    }
    center = _nrrdCenter(nin->axis[ai].center);
    minsmp = nrrdCenterCell == center ? 1 : 2;
    if (!( nin->axis[ai].size >= minsmp && info->samples[ai] >= minsmp )) {
      sprintf(err, "%s: axis %d # input samples (" _AIR_SIZE_T_CNV 
              ") or output samples (" _AIR_SIZE_T_CNV ") "
              " invalid for %s centering",
              me, ai, nin->axis[ai].size, info->samples[ai],
              airEnumStr(nrrdCenter, center));
      biffAdd(NRRD, err); return 1;
    }
  }
  return 0;
}
Example #7
0
void
_nrrdMeasureLineError(void *ans, int ansType,
                      const void *line, int lineType, size_t len, 
                      double axmin, double axmax) {
  double x, y, slope, intc, tmp, err=0, (*lup)(const void*, size_t);
  size_t ii;
  
  _nrrdMeasureLineFit(&intc, &slope, line, lineType, len, axmin, axmax);

  if (!( AIR_EXISTS(axmin) && AIR_EXISTS(axmax) )) {
    axmin = 0;
    axmax = len-1;
  }
  lup = nrrdDLookup[lineType];
  for (ii=0; ii<len; ii++) {
    x = NRRD_NODE_POS(axmin, axmax, len, ii);
    y = lup(line, ii);
    tmp = slope*x + intc - y;
    err += tmp*tmp;
  }
  nrrdDStore[ansType](ans, err);
}
Example #8
0
void
_nrrdMeasureMean(void *ans, int ansType,
                 const void *line, int lineType, size_t len, 
                 double axmin, double axmax) {
  double val, S, M, (*lup)(const void*, size_t);
  size_t ii, count;

  AIR_UNUSED(axmin);
  AIR_UNUSED(axmax);
  lup = nrrdDLookup[lineType];
  if (nrrdTypeIsIntegral[lineType]) {
    S = 0.0;
    for (ii=0; ii<len; ii++) {
      S += lup(line, ii);
    }
    M = S/len;
  } else {
    S = AIR_NAN;
    for (ii=0; !AIR_EXISTS(S) && ii<len; ii++) {
      S = lup(line, ii);
    }
    if (AIR_EXISTS(S)) {
      /* there was an existant value */
      count = 1;
      for (; ii<len; ii++) {
        val = lup(line, ii);
        if (AIR_EXISTS(val)) {
          count++;
          S += val;
        }
      }
      M = S/count;
    } else {
      /* there were NO existant values */
      M = AIR_NAN;
    }
  }
  nrrdDStore[ansType](ans, M);
}
Example #9
0
void
_nrrdMeasureMedian(void *ans, int ansType,
                   const void *_line, int lineType, size_t len, 
                   double axmin, double axmax) {
  double M=0, (*lup)(const void*, size_t);
  size_t ii, mid;
  void *line;

  AIR_UNUSED(axmin);
  AIR_UNUSED(axmax);
  lup = nrrdDLookup[lineType];
  line = calloc(len, nrrdTypeSize[lineType]);
  if (line) {
    memcpy(line, _line, len*nrrdTypeSize[lineType]);
  
    /* yes, I know, this is not the fastest median.  I'll get to it ... */
    qsort(line, len, nrrdTypeSize[lineType], nrrdValCompare[lineType]);
    M = AIR_NAN;
    for (ii=0; !AIR_EXISTS(M) && ii<len; ii++) {
      M = lup(line, ii);
    }
    
    if (AIR_EXISTS(M)) {
      /* i is index AFTER first existant value */
      ii--;
      len -= ii;
      mid = len/2;
      if (len % 2) {
        /* len is odd, there is a middle value, its at mid */
        M = lup(line, ii+mid);
      } else {
        /* len is even, two middle values are at mid-1 and mid */
        M = (lup(line, ii+mid-1) + lup(line, ii+mid))/2;
      }
    }
  }
  nrrdDStore[ansType](ans, M);
}
Example #10
0
int
baneInputCheck (Nrrd *nin, baneHVolParm *hvp) {
  char me[]="baneInputCheck", err[BIFF_STRLEN];
  int i;

  if (nrrdCheck(nin)) {
    sprintf(err, "%s: basic nrrd validity check failed", me);
    biffMove(BANE, err, NRRD); return 1;
  }
  if (3 != nin->dim) {
    sprintf(err, "%s: need a 3-dimensional nrrd (not %d)", me, nin->dim);
    biffAdd(BANE, err); return 1;
  }
  if (nrrdTypeBlock == nin->type) {
    sprintf(err, "%s: can't operate on block type", me);
    biffAdd(BANE, err); return 1;
  }
  if (!( AIR_EXISTS(nin->axis[0].spacing) && nin->axis[0].spacing != 0 &&
         AIR_EXISTS(nin->axis[1].spacing) && nin->axis[1].spacing != 0 &&
         AIR_EXISTS(nin->axis[2].spacing) && nin->axis[2].spacing != 0 )) {
    sprintf(err, "%s: must have non-zero existant spacing for all 3 axes", me);
    biffAdd(BANE, err); return 1;
  }
  for (i=0; i<=2; i++) {
    if (_baneAxisCheck(hvp->axis + i)) {
      sprintf(err, "%s: trouble with axis %d", me, i);
      biffAdd(BANE, err); return 1;
    }
  }
  if (!hvp->clip) {
    sprintf(err, "%s: got NULL baneClip", me);
    biffAdd(BANE, err); return 1;
  }

  /* all okay */
  return 0;
}
Example #11
0
int
_nrrdSpaceVecExists(const Nrrd *nrrd, unsigned int axi) {
  unsigned int sai;
  int ret;

  if (!( nrrd && axi < nrrd->dim && nrrd->spaceDim )) {
    ret = AIR_FALSE;
  } else {
    ret = AIR_TRUE;
    for (sai=0; sai<nrrd->spaceDim; sai++) {
      ret &= AIR_EXISTS(nrrd->axis[axi].spaceDirection[sai]);
    }
  }
  return ret;
}
Example #12
0
void
_nrrdMeasureHistoMin(void *ans, int ansType,
                     const void *line, int lineType, size_t len, 
                     double axmin, double axmax) {
  double val, (*lup)(const void*, size_t);
  size_t ii;

  if (!(AIR_EXISTS(axmin) && AIR_EXISTS(axmax))) {
    axmin = -0.5;
    axmax = len-0.5;
  }
  lup = nrrdDLookup[lineType];
  for (ii=0; ii<len; ii++) {
    if (lup(line, ii) > 0) {
      break;
    }
  }
  if (ii==len) {
    nrrdDStore[ansType](ans, AIR_NAN);
    return;
  }
  val = NRRD_CELL_POS(axmin, axmax, len, ii);
  nrrdDStore[ansType](ans, val);
}
Example #13
0
baneClip *
baneClipNew(int type, double *parm) {
  static const char me[]="baneClipNew";
  baneClip *clip;

  if (!( AIR_IN_OP(baneClipUnknown, type, baneClipLast) )) {
    biffAddf(BANE, "%s: baneClip %d invalid", me, type);
    return NULL;
  }
  if (!parm) {
    biffAddf(BANE, "%s: got NULL pointer", me);
    return NULL;
  }
  if (!(AIR_EXISTS(parm[0]))) {
    biffAddf(BANE, "%s: parm[0] doesn't exist", me);
    return NULL;
  }
  clip = (baneClip*)calloc(1, sizeof(baneClip));
  if (!clip) {
    biffAddf(BANE, "%s: couldn't allocate baneClip!", me);
    return NULL;
  }
  clip->parm[0] = parm[0];
  clip->type = type;
  switch(type) {
  case baneClipAbsolute:
    sprintf(clip->name, "absolute");
    clip->answer = _baneClipAnswer_Absolute;
    break;
  case baneClipPeakRatio:
    sprintf(clip->name, "peak ratio");
    clip->answer = _baneClipAnswer_PeakRatio;
    break;
  case baneClipPercentile:
    sprintf(clip->name, "percentile");
    clip->answer = _baneClipAnswer_Percentile;
    break;
  case baneClipTopN:
    sprintf(clip->name, "top N");
    clip->answer = _baneClipAnswer_TopN;
    break;
  default:
    biffAddf(BANE, "%s: sorry, baneClip %d not implemented", me, type);
    baneClipNix(clip); return NULL;
    break;
  }
  return clip;
}
Example #14
0
/*
******** nrrdSpacingCalculate
**
** Determine nrrdSpacingStatus, and whatever can be calculated about
** spacing for a given axis.  Takes a nrrd, an axis, a double pointer
** (for returning a scalar), a space vector, and an int pointer for
** returning the known length of the space vector.
**
** The behavior of what has been set by the function is determined by
** the return value, which takes values from the nrrdSpacingStatus*
** enum, as follows:
**
** returned status value:            what it means, and what it set
** ---------------------------------------------------------------------------
** nrrdSpacingStatusUnknown          Something about the given arguments is
**                                   invalid.
**                                   *spacing = NaN,
**                                   vector = all NaNs
**
** nrrdSpacingStatusNone             There is no spacing info at all:
**                                   *spacing = NaN,
**                                   vector = all NaNs
**
** nrrdSpacingStatusScalarNoSpace    There is no surrounding space, but the
**                                   axis's spacing was known.
**                                   *spacing = axis->spacing,
**                                   vector = all NaNs
**
** nrrdSpacingStatusScalarWithSpace  There *is* a surrounding space, but the
**                                   given axis does not live in that space,
**                                   because it has no space direction.  Caller
**                                   may want to think about what's going on.
**                                   *spacing = axis->spacing,
**                                   vector = all NaNs
**
** nrrdSpacingStatusDirection        There is a surrounding space, in which
**                                   this axis has a direction V:
**                                   *spacing = |V| (length of direction),
**                                   vector = V/|V| (normalized direction)
**                                   NOTE: it is still possible for both
**                                   *spacing and vector to be all NaNs!!
*/
int
nrrdSpacingCalculate(const Nrrd *nrrd, unsigned int ax,
                     double *spacing, double vector[NRRD_SPACE_DIM_MAX]) {
  int ret;
  
  if (!( nrrd && spacing && vector
         && ax <= nrrd->dim-1
         && !_nrrdCheck(nrrd, AIR_FALSE, AIR_FALSE) )) {
    /* there's a problem with the arguments.  Note: the _nrrdCheck()
       call does not check on non-NULL-ity of nrrd->data */
    ret = nrrdSpacingStatusUnknown;
    if (spacing) { 
      *spacing = AIR_NAN;
    }
    if (vector) {
      nrrdSpaceVecSetNaN(vector);
    }
  } else {
    if (AIR_EXISTS(nrrd->axis[ax].spacing)) {
      if (nrrd->spaceDim > 0) {
        ret = nrrdSpacingStatusScalarWithSpace;
      } else {
        ret = nrrdSpacingStatusScalarNoSpace;
      }
      *spacing = nrrd->axis[ax].spacing;
      nrrdSpaceVecSetNaN(vector);      
    } else {
      if (nrrd->spaceDim > 0 && _nrrdSpaceVecExists(nrrd, ax)) {
        ret = nrrdSpacingStatusDirection;
        *spacing = nrrdSpaceVecNorm(nrrd->spaceDim, 
                                    nrrd->axis[ax].spaceDirection);
        nrrdSpaceVecScale(vector, 1.0/(*spacing),
                          nrrd->axis[ax].spaceDirection);
      } else {
        ret = nrrdSpacingStatusNone;
        *spacing = AIR_NAN;
        nrrdSpaceVecSetNaN(vector);
      }
    }
  }
  return ret;
}
Example #15
0
dyeColor *
dyeColorSet(dyeColor *col, int space, float v0, float v1, float v2) {

  if (col && DYE_VALID_SPACE(space)) {
    col->ii = AIR_CLAMP(0, col->ii, 1);

    /* We switch to the other one if the current one seems to be used,
       but we don't switch if new and current colorspaces are the same.
       If the other one is being used too, oh well.  */
    if (dyeSpaceUnknown != col->spc[col->ii] &&
        AIR_EXISTS(col->val[col->ii][0]) &&
        col->spc[col->ii] != space) {
      col->ii = 1 - col->ii;
    }

    ELL_3V_SET(col->val[col->ii], v0, v1, v2);
    col->spc[col->ii] = space;
  }
  return col;
}
void
_nrrdStrcatSpaceVector(char *str, unsigned int spaceDim,
                       const double val[NRRD_SPACE_DIM_MAX]) {
  char buff[AIR_STRLEN_MED];  /* bad Gordon */
  unsigned int dd;

  if (AIR_EXISTS(val[0])) {
    strcat(str, "(");
    for (dd=0; dd<spaceDim; dd++) {
      strcpy(buff, "");
      airSinglePrintf(NULL, buff, "%.17g", val[dd]);
      strcat(str, buff);
      sprintf(buff, "%s", dd+1 < spaceDim ? "," : ")");
      strcat(str, buff);
    }
  } else {
    strcat(str, _nrrdNoSpaceVector);
  }
  return;
}
Example #17
0
void
_nrrdMeasureVariance(void *ans, int ansType,
                     const void *line, int lineType, size_t len, 
                     double axmin, double axmax) {
  double val, S, SS, (*lup)(const void*, size_t);
  size_t ii, count;

  AIR_UNUSED(axmin);
  AIR_UNUSED(axmax);
  SS = S = 0.0;
  lup = nrrdDLookup[lineType];
  if (nrrdTypeIsIntegral[lineType]) {
    for (ii=0; ii<len; ii++) {
      val = lup(line, ii);
      S += val;
      SS += val*val;
    }
    S /= len;
    SS /= len;
  } else {
    count = 0;
    for (ii=0; ii<len; ii++) {
      val = lup(line, ii);
      if (AIR_EXISTS(val)) {
        count++;
        S += val;
        SS += val*val;
      }
    }
    if (count) {
      S /= count;
      SS /= count;
    } else {
      S = SS = AIR_NAN;
    }
  }
  nrrdDStore[ansType](ans, SS - S*S);
}
Example #18
0
void
nrrdAxisInfoMinMaxSet(Nrrd *nrrd, unsigned int ax, int defCenter) {
  int center;
  double spacing;

  if (!( nrrd && ax <= nrrd->dim-1 )) {
    return;
  }
  
  center = _nrrdCenter2(nrrd->axis[ax].center, defCenter);
  spacing = nrrd->axis[ax].spacing;
  if (!AIR_EXISTS(spacing))
    spacing = nrrdDefaultSpacing;
  if (nrrdCenterCell == center) {
    nrrd->axis[ax].min = 0;
    nrrd->axis[ax].max = spacing*nrrd->axis[ax].size;
  } else {
    nrrd->axis[ax].min = 0;
    nrrd->axis[ax].max = spacing*(nrrd->axis[ax].size - 1);
  }
  
  return;
}
Example #19
0
int
baneHVolCheck (Nrrd *hvol) {
  char me[]="baneHVolCheck", err[BIFF_STRLEN];

  if (3 != hvol->dim) {
    sprintf(err, "%s: need dimension to be 3 (not %d)", me, hvol->dim);
    biffAdd(BANE, err); return 1;
  }
  if (nrrdTypeUChar != hvol->type) {
    sprintf(err, "%s: need type to be %s (not %s)", 
            me, airEnumStr(nrrdType, nrrdTypeUChar),
            airEnumStr(nrrdType, hvol->type));
    biffAdd(BANE, err); return 1;
  }
  if (!( AIR_EXISTS(hvol->axis[0].min) && AIR_EXISTS(hvol->axis[0].max) && 
         AIR_EXISTS(hvol->axis[1].min) && AIR_EXISTS(hvol->axis[1].max) && 
         AIR_EXISTS(hvol->axis[2].min) && AIR_EXISTS(hvol->axis[2].max) )) {
    sprintf(err, "%s: axisMin and axisMax must be set for all axes", me);
    biffAdd(BANE, err); return 1;
  }
  /* 
  ** NOTE: For the time being, I'm giving up on enforcing a 
  ** particular kind of histogram volume ...
  if (strcmp(hvol->axis[0].label, baneMeasrGradMag->name)) {
    sprintf(err, "%s: expected \"%s\" on axis 0 label",
            me, baneMeasrGradMag->name);
    biffAdd(BANE, err); return 1;
  }
  if (strcmp(hvol->axis[1].label, baneMeasrLapl->name) &&
      strcmp(hvol->axis[1].label, baneMeasrHess->name)) {
    sprintf(err, "%s: expected a 2nd deriv. measr on axis 1 (%s or %s)",
            me, baneMeasrHess->name, baneMeasrLapl->name);
    biffAdd(BANE, err); return 1;    
  }
  if (strcmp(hvol->axis[2].label, baneMeasrVal->name)) {
    sprintf(err, "%s: expected \"%s\" on axis 2",
            me, baneMeasrVal->name);
    biffAdd(BANE, err); return 1;
  }
  */
  return 0;
}
Example #20
0
/*
******** nrrdAxisInfoSet_nva()
**
** Simple means of setting fields of the axis array in the nrrd.
**
** type to pass for third argument:
**           nrrdAxisInfoSize: size_t*
**        nrrdAxisInfoSpacing: double*
**      nrrdAxisInfoThickness: double*
**            nrrdAxisInfoMin: double*
**            nrrdAxisInfoMax: double*
** nrrdAxisInfoSpaceDirection: double (*var)[NRRD_SPACE_DIM_MAX]
**         nrrdAxisInfoCenter: int*
**           nrrdAxisInfoKind: int*
**          nrrdAxisInfoLabel: char**
**          nrrdAxisInfoUnits: char**
*/
void
nrrdAxisInfoSet_nva(Nrrd *nrrd, int axInfo, const void *_info) {
  _nrrdAxisInfoSetPtrs info;
  int exists;
  unsigned int ai, si, minsi;
  
  if (!( nrrd 
         && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX) 
         && AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast) 
         && _info )) {
    return;
  }
  info.P = _info;

  for (ai=0; ai<nrrd->dim; ai++) {
    switch (axInfo) {
    case nrrdAxisInfoSize:
      nrrd->axis[ai].size = info.ST[ai];
      break;
    case nrrdAxisInfoSpacing:
      nrrd->axis[ai].spacing = info.D[ai];
      break;
    case nrrdAxisInfoThickness:
      nrrd->axis[ai].thickness = info.D[ai];
      break;
    case nrrdAxisInfoMin:
      nrrd->axis[ai].min = info.D[ai];
      break;
    case nrrdAxisInfoMax:
      nrrd->axis[ai].max = info.D[ai];
      break;
    case nrrdAxisInfoSpaceDirection:
      /* we won't allow setting an invalid direction */
      exists = AIR_EXISTS(info.V[ai][0]);
      minsi = nrrd->spaceDim;
      for (si=0; si<nrrd->spaceDim; si++) {
        nrrd->axis[ai].spaceDirection[si] = info.V[ai][si];
        if (exists ^ AIR_EXISTS(info.V[ai][si])) {
          minsi = 0;
          break;
        }
      }
      for (si=minsi; si<NRRD_SPACE_DIM_MAX; si++) {
        nrrd->axis[ai].spaceDirection[si] = AIR_NAN;
      }
      break;
    case nrrdAxisInfoCenter:
      nrrd->axis[ai].center = info.I[ai];
      break;
    case nrrdAxisInfoKind:
      nrrd->axis[ai].kind = info.I[ai];
      break;
    case nrrdAxisInfoLabel:
      nrrd->axis[ai].label = (char *)airFree(nrrd->axis[ai].label);
      nrrd->axis[ai].label = (char *)airStrdup(info.CP[ai]);
      break;
    case nrrdAxisInfoUnits:
      nrrd->axis[ai].units = (char *)airFree(nrrd->axis[ai].units);
      nrrd->axis[ai].units = (char *)airStrdup(info.CP[ai]);
      break;
    }
  }
  if (nrrdAxisInfoSpaceDirection == axInfo) {
    for (ai=nrrd->dim; ai<NRRD_DIM_MAX; ai++) {
      for (si=0; si<NRRD_SPACE_DIM_MAX; si++) {
        nrrd->axis[ai].spaceDirection[si] = AIR_NAN;
      }
    }    
  }
  return;
}
Example #21
0
/*
** asserts all the properties associated with orientation information
**
** The most important part of this is asserting the per-axis mutual
** exclusion of min/max/spacing/units versus using spaceDirection.
*/
static int
_nrrdFieldCheckSpaceInfo(const Nrrd *nrrd, int useBiff) {
  static const char me[]="_nrrdFieldCheckSpaceInfo";
  unsigned int dd, ii;
  int exists;

  if (!( !nrrd->space || !airEnumValCheck(nrrdSpace, nrrd->space) )) {
    biffMaybeAddf(useBiff, NRRD, "%s: space %d invalid",
                  me, nrrd->space);
    return 1;
  }
  if (!( nrrd->spaceDim <= NRRD_SPACE_DIM_MAX )) {
    biffMaybeAddf(useBiff, NRRD, "%s: space dimension %d is outside "
                  "valid range [0,NRRD_SPACE_DIM_MAX] = [0,%d]",
                  me, nrrd->dim, NRRD_SPACE_DIM_MAX);
    return 1;
  }
  if (nrrd->spaceDim) {
    if (nrrd->space) {
      if (nrrdSpaceDimension(nrrd->space) != nrrd->spaceDim) {
        biffMaybeAddf(useBiff, NRRD,
                      "%s: space %s has dimension %d but spaceDim is %d",
                      me, airEnumStr(nrrdSpace, nrrd->space),
                      nrrdSpaceDimension(nrrd->space), nrrd->spaceDim);
        return 1;
      }
    }
    /* check that all coeffs of spaceOrigin have consistent existance */
    exists = AIR_EXISTS(nrrd->spaceOrigin[0]);
    for (ii=0; ii<nrrd->spaceDim; ii++) {
      if (exists ^ AIR_EXISTS(nrrd->spaceOrigin[ii])) {
        biffMaybeAddf(useBiff, NRRD,
                      "%s: existance of space origin coefficients must "
                      "be consistent (val[0] not like val[%d])", me, ii);
        return 1;
      }
    }
    /* check that all coeffs of measurementFrame have consistent existance */
    exists = AIR_EXISTS(nrrd->measurementFrame[0][0]);
    for (dd=0; dd<nrrd->spaceDim; dd++) {
      for (ii=0; ii<nrrd->spaceDim; ii++) {
        if (exists ^ AIR_EXISTS(nrrd->measurementFrame[dd][ii])) {
          biffMaybeAddf(useBiff, NRRD,
                        "%s: existance of measurement frame coefficients "
                        "must be consistent: [col][row] [%d][%d] not "
                        "like [0][0])", me, dd, ii);
          return 1;
        }
      }
    }
    /* check on space directions */
    for (dd=0; dd<nrrd->dim; dd++) {
      exists = AIR_EXISTS(nrrd->axis[dd].spaceDirection[0]);
      for (ii=1; ii<nrrd->spaceDim; ii++) {
        if (exists ^ AIR_EXISTS(nrrd->axis[dd].spaceDirection[ii])) {
          biffMaybeAddf(useBiff, NRRD,
                        "%s: existance of space direction %d coefficients "
                        "must be consistent (val[0] not like val[%d])", me,
                        dd, ii); return 1;
        }
      }
      if (exists) {
        if (AIR_EXISTS(nrrd->axis[dd].min)
            || AIR_EXISTS(nrrd->axis[dd].max)
            || AIR_EXISTS(nrrd->axis[dd].spacing)
            || !!airStrlen(nrrd->axis[dd].units)) {
          biffMaybeAddf(useBiff, NRRD,
                        "%s: axis[%d] has a direction vector, and so can't "
                        "have min, max, spacing, or units set", me, dd);
          return 1;
        }
      }
    }
  } else {
    /* else there's not supposed to be anything in "space" */
    if (nrrd->space) {
      biffMaybeAddf(useBiff, NRRD,
                    "%s: space %s can't be set with spaceDim %d",
                    me, airEnumStr(nrrdSpace, nrrd->space),
                    nrrd->spaceDim);
      return 1;
    }
    /* -------- */
    exists = AIR_FALSE;
    for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
      exists |= !!airStrlen(nrrd->spaceUnits[dd]);
    }
    if (exists) {
      biffMaybeAddf(useBiff, NRRD,
                    "%s: spaceDim is 0, but space units is set", me);
      return 1;
    }
    /* -------- */
    exists = AIR_FALSE;
    for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
      exists |= AIR_EXISTS(nrrd->spaceOrigin[dd]);
    }
    if (exists) {
      biffMaybeAddf(useBiff, NRRD,
                    "%s: spaceDim is 0, but space origin is set", me);
      return 1;
    }
    /* -------- */
    exists = AIR_FALSE;
    for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
      for (ii=0; ii<NRRD_DIM_MAX; ii++) {
        exists |= AIR_EXISTS(nrrd->axis[ii].spaceDirection[dd]);
      }
    }
    if (exists) {
      biffMaybeAddf(useBiff, NRRD,
                    "%s: spaceDim is 0, but space directions are set", me);
      return 1;
    }
  }
  return 0;
}
Example #22
0
/*
******** nrrdOriginCalculate
**
** makes an effort to calculate something like an "origin" (as in
** nrrd->spaceOrigin) from the per-axis min, max, or spacing, when
** there is no real space information.  Like the spaceOrigin, this
** location is supposed to be THE CENTER of the first sample.  To
** avoid making assumptions about the nrrd or the caller, a default
** sample centering (defaultCenter) has to be provided (use either
** nrrdCenterNode or nrrdCenterCell).  The axes that are used
** for the origin calculation have to be given explicitly- but they
** are likely the return of nrrdDomainAxesGet
**
** The computed origin is put into the given vector (origin).  The return
** value takes on values from the nrrdOriginStatus* enum:
**
** nrrdOriginStatusUnknown:        invalid arguments (e.g. NULL pointer, or
**                                 axis values out of range)
**
** nrrdOriginStatusDirection:      the chosen axes have spaceDirection set,
**                                 which means caller should instead be using
**                                 nrrdSpaceOriginGet
**
** nrrdOriginStatusNoMin:          can't compute "origin" without axis->min
**
** nrrdOriginStatusNoMaxOrSpacing: can't compute origin without (axis->min
**                                 and) either axis->max or axis->spacing
**
** nrrdOriginStatusOkay:           all is well
*/
int
nrrdOriginCalculate(const Nrrd *nrrd,
                    unsigned int *axisIdx, unsigned int axisIdxNum,
                    int defaultCenter, double *origin) {
  const NrrdAxisInfo *axis[NRRD_SPACE_DIM_MAX];
  int center, okay, gotSpace, gotMin, gotMaxOrSpacing;
  unsigned int ai;
  double min, spacing;

#define ERROR \
  if (origin) { \
    for (ai=0; ai<axisIdxNum; ai++) { \
      origin[ai] = AIR_NAN; \
    } \
  }

  if (!( nrrd
         && (nrrdCenterCell == defaultCenter
             || nrrdCenterNode == defaultCenter)
         && origin )) {
    ERROR;
    return nrrdOriginStatusUnknown;
  }

  okay = AIR_TRUE;
  for (ai=0; ai<axisIdxNum; ai++) {
    okay &= axisIdx[ai] < nrrd->dim;
  }
  if (!okay) {
    ERROR;
    return nrrdOriginStatusUnknown;
  }

  /* learn axisInfo pointers */
  for (ai=0; ai<axisIdxNum; ai++) {
    axis[ai] = nrrd->axis + axisIdx[ai];
  }

  gotSpace = AIR_FALSE;
  for (ai=0; ai<axisIdxNum; ai++) {
    gotSpace |= AIR_EXISTS(axis[ai]->spaceDirection[0]);
  }
  if (nrrd->spaceDim > 0 && gotSpace) {
    ERROR;
    return nrrdOriginStatusDirection;
  }

  gotMin = AIR_TRUE;
  for (ai=0; ai<axisIdxNum; ai++) {
    gotMin &= AIR_EXISTS(axis[0]->min);
  }
  if (!gotMin) {
    ERROR;
    return nrrdOriginStatusNoMin;
  }

  gotMaxOrSpacing = AIR_TRUE;
  for (ai=0; ai<axisIdxNum; ai++) {
    gotMaxOrSpacing &= (AIR_EXISTS(axis[ai]->max)
                        || AIR_EXISTS(axis[ai]->spacing));
  }
  if (!gotMaxOrSpacing) {
    ERROR;
    return nrrdOriginStatusNoMaxOrSpacing;
  }

  for (ai=0; ai<axisIdxNum; ai++) {
    size_t size;
    double denom;
    size = axis[ai]->size;
    min = axis[ai]->min;
    center = (nrrdCenterUnknown != axis[ai]->center
              ? axis[ai]->center
              : defaultCenter);
    denom = AIR_CAST(double, nrrdCenterCell == center ? size : size-1);
    spacing = (AIR_EXISTS(axis[ai]->spacing)
               ? axis[ai]->spacing
               : (axis[ai]->max - min)/denom);
    origin[ai] = min + (nrrdCenterCell == center ? spacing/2 : 0);
  }
  return nrrdOriginStatusOkay;
}
Example #23
0
int
main(int argc, char *argv[]) {
  char *me, *err, *outS;
  hestOpt *hopt=NULL;
  airArray *mop;

  int numGrth, numDtdi, numGrgr, numDtgr, numNrrd, ni;
  plotPS pps;
  plotParm pparm;
  Nrrd **_ndata, **ndata;

  mop = airMopNew();
  
  me = argv[0];

  hestOptAdd(&hopt, "i", "data", airTypeOther, 1, -1, &_ndata, NULL,
             "input nrrd containing data to plot",
             &numNrrd, NULL, nrrdHestNrrd);
  hestOptAdd(&hopt, "dbox", "minX minY maxX maxY", airTypeDouble,
             4, 4, pparm.dbox, NULL,
             "bounding box, in data space");
  
  hestOptAdd(&hopt, "bbox", "minX minY maxX maxY", airTypeDouble,
             4, 4, pps.bbox, NULL,
             "bounding box, in graph space");
  hestOptAdd(&hopt, "psc", "PS scale", airTypeDouble, 1, 1, &(pps.psc), "300",
             "scaling from graph space to PostScript points");
  hestOptAdd(&hopt, "nobg", NULL, airTypeInt, 0, 0, &(pps.nobg), NULL,
             "don't fill with background color");
  hestOptAdd(&hopt, "bg", "background", airTypeDouble, 3, 3,
             &(pps.bgColor), "1 1 1",
             "background RGB color; each component in range [0.0,1.0]");
  
  hestOptAdd(&hopt, "grth", "graph thickness", airTypeDouble,
             1, -1, &(pparm.graphThick), "0.01",
             "thickness of line for graph, or \"0\" for no graph line", 
             &numGrth);
  hestOptAdd(&hopt, "grgr", "graph gray", airTypeDouble,
             1, -1, &(pparm.graphGray), "0",
             "grayscale to use for graph", &numGrgr);
  hestOptAdd(&hopt, "dtdi", "dot diameter", airTypeDouble,
             1, -1, &(pparm.dotDiameter), "0.1",
             "radius of dot drawn at data points, or \"0\" for no dots",
             &numDtdi);
  hestOptAdd(&hopt, "dtgr", "dot gray", airTypeDouble,
             1, -1, &(pparm.dotGray), "0",
             "grayscale to use for dots", &numDtgr);
  hestOptAdd(&hopt, "dtid", "dot inner diam frac", airTypeDouble,
             1, 1, &(pparm.dotInnerDiameterFraction), "0.0",
             "fractional radius of white dot drawn within dot");

  hestOptAdd(&hopt, "tihz", "pos", airTypeDouble,
             0, -1, &(pparm.horzTick), "",
             "locations for tickmarks on horizontal axis",
             &(pparm.numHorzTick));
  hestOptAdd(&hopt, "tivt", "pos", airTypeDouble,
             0, -1, &(pparm.vertTick), "",
             "locations for tickmarks on vertical axis",
             &(pparm.numVertTick));
  hestOptAdd(&hopt, "tiho", "offset", airTypeDouble,
             1, 1, &(pparm.horzTickLabelOffset), "0",
             "horizontal tick label offset");
  hestOptAdd(&hopt, "tivo", "offset", airTypeDouble,
             1, 1, &(pparm.vertTickLabelOffset), "0",
             "vertical tick label offset");
  hestOptAdd(&hopt, "tils", "size", airTypeDouble,
             1, 1, &(pparm.tickLabelSize), "0",
             "font size for labels on tick marks, or \"0\" for no labels");
  hestOptAdd(&hopt, "tith", "tick thickness", airTypeDouble,
             1, 1, &(pparm.tickThick), "0.01",
             "thickness of lines for tick marks");
  hestOptAdd(&hopt, "tiln", "tick length", airTypeDouble,
             1, 1, &(pparm.tickLength), "0.08",
             "length of lines for tick marks");

  hestOptAdd(&hopt, "axth", "axis thickness", airTypeDouble,
             1, 1, &(pparm.axisThick), "0.01",
             "thickness of lines for axes");
  hestOptAdd(&hopt, "axor", "axis origin", airTypeDouble,
             2, 2, &(pparm.axisOrig), "0 0",
             "origin of lines for axes, in data space");
  hestOptAdd(&hopt, "axhl", "horiz axis label", airTypeString,
             1, 1, &(pparm.axisHorzLabel), "",
             "label on horizontal axis");
  hestOptAdd(&hopt, "axvl", "vert axis label", airTypeString,
             1, 1, &(pparm.axisVertLabel), "",
             "label on vertical axis");

  hestOptAdd(&hopt, "o", "output PS", airTypeString,
             1, 1, &outS, "out.ps",
             "output file to render postscript into");
  hestParseOrDie(hopt, argc-1, argv+1, NULL,
                 me, info, AIR_TRUE, AIR_TRUE, AIR_TRUE);
  airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways);
  airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways);

  if (!( numGrth == numDtdi 
         && numDtdi == numGrgr
         && numGrgr == numDtgr )) {
    fprintf(stderr, "%s: number of arguments given to grth (%d), dtdi (%d), "
            "grgr (%d), dtgr (%d) not all equal\n", me,
            numGrth, numDtdi, numGrgr, numDtgr);
    airMopError(mop); return 1;
  }
  if (!( numNrrd == numGrth )) {
    fprintf(stderr, "%s: number of nrrds (%d) != number graph options (%d)\n",
            me, numNrrd, numGrth);
    airMopError(mop); return 1;
  }

  /* check nrrds */
  for (ni=0; ni<numNrrd; ni++) {
    if (!( (1 == _ndata[ni]->dim || 2 == _ndata[ni]->dim) 
           && nrrdTypeBlock != _ndata[ni]->type )) {
      fprintf(stderr, "%s: input nrrd must be 1-D or 2-D array of scalars",
              me);
      airMopError(mop); return 1;
    }
  }
  ndata = (Nrrd**)calloc(numNrrd, sizeof(Nrrd *));
  airMopAdd(mop, ndata, airFree, airMopAlways);
  for (ni=0; ni<numNrrd; ni++) {
    ndata[ni] = nrrdNew();
    airMopAdd(mop, ndata[ni], (airMopper)nrrdNuke, airMopAlways);
    if (nrrdConvert(ndata[ni], _ndata[ni], nrrdTypeDouble)) {
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: couldn't convert input %d to %s:\n%s\n",
              me, ni, airEnumStr(nrrdType, nrrdTypeDouble), err);
      airMopError(mop); return 1;
    }
    if (1 == ndata[ni]->dim) {
      if (nrrdAxesInsert(ndata[ni], ndata[ni], 0)) {
        airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
        fprintf(stderr, "%s: couldn't insert axis 0 on nrrd %d:\n%s\n",
                me, ni, err);
        airMopError(mop); return 1;
      }
    }
    /* currently assuming node centering */
    if (!AIR_EXISTS(ndata[ni]->axis[1].min)) {
      ndata[ni]->axis[1].min = 0;
    }
    if (!AIR_EXISTS(ndata[ni]->axis[1].max)) {
      ndata[ni]->axis[1].max = ndata[ni]->axis[1].size-1;
    }
  }

  if (!(pps.file = airFopen(outS, stdout, "wb"))) {
    fprintf(stderr, "%s: couldn't open output file\n", me);
    airMopError(mop); return 1;
  }
  airMopAdd(mop, pps.file, (airMopper)airFclose, airMopAlways);
  
  plotPreamble(&pps, &pparm);
  plotAxes(&pps, &pparm, ndata[0]);
  for (ni=0; ni<numNrrd; ni++) {
    plotGraph(&pps, &pparm, ndata, ni);
    plotDots(&pps, &pparm, ndata, ni);
  }
  plotEpilog(&pps, &pparm);

  airMopOkay(mop);
  return 0;
}
Example #24
0
/*
** _nrrdApply2DSetUp()
**
** some error checking and initializing needed for 2D LUTS and regular
** maps.  The intent is that if this succeeds, then there is no need
** for any further error checking.
**
** The only thing this function DOES is allocate the output nrrd, and
** set meta information.  The rest is just error checking.
**
** The given NrrdRange has to be fleshed out by the caller: it can't
** be NULL, and both range->min and range->max must exist.
*/
int
_nrrdApply2DSetUp(Nrrd *nout, const Nrrd *nin,
                  const NrrdRange *range0, const NrrdRange *range1,
                  const Nrrd *nmap, int kind, int typeOut,
                  int rescale0, int rescale1) {
  char me[]="_nrrdApply2DSetUp", err[BIFF_STRLEN], *mapcnt;
  char nounStr[][AIR_STRLEN_SMALL]={"2D lut",
                                    "2D regular map"};
  char verbStr[][AIR_STRLEN_SMALL]={"lut2",
                                    "rmap2"};
  int mapAxis, copyMapAxis0=AIR_FALSE, axisMap[NRRD_DIM_MAX];
  unsigned int dim, entLen;
  size_t size[NRRD_DIM_MAX];
  double domMin, domMax;

  if (nout == nin) {
    sprintf(err, "%s: due to laziness, nout==nin always disallowed", me);
    biffAdd(NRRD, err); return 1;
  }
  if (airEnumValCheck(nrrdType, typeOut)) {
    sprintf(err, "%s: invalid requested output type %d", me, typeOut);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdTypeBlock == nin->type || nrrdTypeBlock == typeOut) {
    sprintf(err, "%s: input or requested output type is %s, need scalar",
            me, airEnumStr(nrrdType, nrrdTypeBlock));
    biffAdd(NRRD, err); return 1;
  }
  if (!(2 == nin->axis[0].size)) {
    sprintf(err, "%s: input axis[0] must have size 2 (not " 
            _AIR_SIZE_T_CNV ")", me, nin->axis[0].size);
    biffAdd(NRRD, err); return 1;
  }
  if (!(nin->dim > 1)) {
    sprintf(err, "%s: input dimension must be > 1 (not %u)", me, nin->dim);
    biffAdd(NRRD, err); return 1;
  }
  if (rescale0 && !(range0
                    && AIR_EXISTS(range0->min) 
                    && AIR_EXISTS(range0->max))) {
    sprintf(err, "%s: want axis 0 rescaling but didn't get range, or "
            "not both range->{min,max} exist", me);
    biffAdd(NRRD, err); return 1;
  }
  if (rescale1 && !(range1
                    && AIR_EXISTS(range1->min) 
                    && AIR_EXISTS(range1->max))) {
    sprintf(err, "%s: want axis 1 rescaling but didn't get range, or "
            "not both range->{min,max} exist", me);
    biffAdd(NRRD, err); return 1;
  }
  mapAxis = nmap->dim - 2;
  if (!(0 == mapAxis || 1 == mapAxis)) {
    sprintf(err, "%s: dimension of %s should be 2 or 3, not %d", 
            me, nounStr[kind], nmap->dim);
    biffAdd(NRRD, err); return 1;
  }
  copyMapAxis0 = (1 == mapAxis);
  domMin = _nrrdApplyDomainMin(nmap, AIR_FALSE, mapAxis);
  domMax = _nrrdApplyDomainMax(nmap, AIR_FALSE, mapAxis);
  if (!( domMin < domMax )) {
    sprintf(err, "%s: (axis %d) domain min (%g) not less than max (%g)", me,
            mapAxis, domMin, domMax);
    biffAdd(NRRD, err); return 1;
  }
  domMin = _nrrdApplyDomainMin(nmap, AIR_FALSE, mapAxis+1);
  domMax = _nrrdApplyDomainMax(nmap, AIR_FALSE, mapAxis+1);
  if (!( domMin < domMax )) {
    sprintf(err, "%s: (axis %d) domain min (%g) not less than max (%g)", me,
            mapAxis+1, domMin, domMax);
    biffAdd(NRRD, err); return 1;
  }
  if (nrrdHasNonExist(nmap)) {
    sprintf(err, "%s: %s nrrd has non-existent values",
            me, nounStr[kind]);
    biffAdd(NRRD, err); return 1;
  }
  entLen = mapAxis ? nmap->axis[0].size : 1;
  if (mapAxis + nin->dim - 1 > NRRD_DIM_MAX) {
    sprintf(err, "%s: input nrrd dim %d through non-scalar %s exceeds "
            "NRRD_DIM_MAX %d",
            me, nin->dim, nounStr[kind], NRRD_DIM_MAX);
    biffAdd(NRRD, err); return 1;
  }
  if (mapAxis) {
    size[0] = entLen;
    axisMap[0] = -1;
  }
  for (dim=1; dim<nin->dim; dim++) {
    size[dim-1+mapAxis] = nin->axis[dim].size;
    axisMap[dim-1+mapAxis] = dim;
  }
  /*
  fprintf(stderr, "##%s: pre maybe alloc: nout->data = %p\n", me, nout->data);
  for (dim=0; dim<mapAxis + nin->dim - 1; dim++) {
    fprintf(stderr, "    size[%d] = %d\n", dim, (int)size[dim]);
  }
  fprintf(stderr, "   nout->dim = %u; nout->type = %d = %s; sizes = %u,%u\n", 
          nout->dim, nout->type,
          airEnumStr(nrrdType, nout->type),
          AIR_CAST(unsigned int, nout->axis[0].size),
          AIR_CAST(unsigned int, nout->axis[1].size));
  fprintf(stderr, "   typeOut = %d = %s\n", typeOut,
          airEnumStr(nrrdType, typeOut));
  */
  if (nrrdMaybeAlloc_nva(nout, typeOut, nin->dim - 1 + mapAxis, size)) {
    sprintf(err, "%s: couldn't allocate output nrrd", me);
    biffAdd(NRRD, err); return 1;
  }
  /*
  fprintf(stderr, "   nout->dim = %d; nout->type = %d = %s\n",
          nout->dim, nout->type,
          airEnumStr(nrrdType, nout->type));
  for (dim=0; dim<nout->dim; dim++) {
    fprintf(stderr, "    size[%d] = %d\n", dim, (int)nout->axis[dim].size);
  }
  fprintf(stderr, "##%s: post maybe alloc: nout->data = %p\n", me, nout->data);
  */
  if (nrrdAxisInfoCopy(nout, nin, axisMap, NRRD_AXIS_INFO_NONE)) {
    sprintf(err, "%s: trouble copying axis info", me);
    biffAdd(NRRD, err); return 1;
  }
  if (copyMapAxis0) {
    _nrrdAxisInfoCopy(nout->axis + 0, nmap->axis + 0,
                      NRRD_AXIS_INFO_SIZE_BIT);
  }

  mapcnt = _nrrdContentGet(nmap);
  if (nrrdContentSet_va(nout, verbStr[kind], nin, "%s", mapcnt)) {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err); free(mapcnt); return 1;
  }
  free(mapcnt); 
  nrrdBasicInfoInit(nout, (NRRD_BASIC_INFO_DATA_BIT
                           | NRRD_BASIC_INFO_TYPE_BIT
                           | NRRD_BASIC_INFO_BLOCKSIZE_BIT
                           | NRRD_BASIC_INFO_DIMENSION_BIT
                           | NRRD_BASIC_INFO_CONTENT_BIT));
  return 0;
}
Example #25
0
/*
** _nrrdApply2DLutOrRegMap()
**
** the guts of nrrdApply2DLut and nrrdApply2DRegMap
**
** yikes, does NOT use biff, since we're only supposed to be called
** after copious error checking.  
**
** FOR INSTANCE, this allows nout == nin, which could be a big
** problem if mapAxis == 1.
**
** we don't need a typeOut arg because nout has already been allocated
** as some specific type; we'll look at that.
**
** NOTE: non-existant values get passed through regular maps and luts
** "unchanged".  However, if the output type is integral, the results
** are probaby undefined.  HEY: there is currently no warning message
** or error handling based on nrrdStateDisallowIntegerNonExist, but
** there really should be.
*/
int
_nrrdApply2DLutOrRegMap(Nrrd *nout, const Nrrd *nin,
                        const NrrdRange *range0, const NrrdRange *range1,
                        const Nrrd *nmap, int ramps,
                        int rescale0, int rescale1) {
  char me[]="_nrrdApply2DLutOrRegMap";
  char *inData, *outData, *mapData, *entData;
  size_t N, I;
  double (*inLoad)(const void *v), (*mapLup)(const void *v, size_t I),
    (*outInsert)(void *v, size_t I, double d),
    val0, val1, domMin0, domMax0, domMin1, domMax1;
  unsigned int i, mapAxis, mapLen0, mapLen1, mapIdx0, mapIdx1,
    entSize, entLen, inSize, outSize;

  mapAxis = nmap->dim - 2;             /* axis of nmap containing entries */
  mapData = (char *)nmap->data;        /* map data, as char* */
                                       /* low end of map domain */
  domMin0 = _nrrdApplyDomainMin(nmap, ramps, mapAxis + 0);
  domMin1 = _nrrdApplyDomainMin(nmap, ramps, mapAxis + 1);
                                       /* high end of map domain */
  domMax0 = _nrrdApplyDomainMax(nmap, ramps, mapAxis + 0);
  domMax1 = _nrrdApplyDomainMax(nmap, ramps, mapAxis + 1);
  mapLen0 = nmap->axis[mapAxis+0].size;   /* number of entries in map axis 0 */
  mapLen1 = nmap->axis[mapAxis+1].size;   /* number of entries in map axis 1 */
  mapLup = nrrdDLookup[nmap->type];    /* how to get doubles out of map */
  inData = (char *)nin->data;          /* input data, as char* */
  inLoad = nrrdDLoad[nin->type];       /* how to get doubles out of nin */
  inSize = nrrdElementSize(nin);       /* size of one input value */
  outData = (char *)nout->data;        /* output data, as char* */
  outInsert = nrrdDInsert[nout->type]; /* putting doubles into output */
  entLen = (mapAxis                    /* number of elements in one entry */
            ? nmap->axis[0].size
            : 1);
  outSize = entLen*nrrdElementSize(nout); /* size of entry in output */
  entSize = entLen*nrrdElementSize(nmap); /* size of entry in map */

  /*
  fprintf(stderr, "!%s: entLen = %u, mapLen = %u,%u\n", me,
          entLen, mapLen0, mapLen1);
  */

  N = nrrdElementNumber(nin)/2;       /* number of value pairs to be mapped */
  /* _VV = 1; */
  if (ramps) {
    fprintf(stderr, "%s: PANIC: unimplemented\n", me);
    exit(1);
  } else {
    /* lookup table */
    for (I=0; I<N; I++) {
      val0 = inLoad(inData + 0*inSize);
      val1 = inLoad(inData + 1*inSize);
      if (rescale0) {
        val0 = AIR_AFFINE(range0->min, val0, range0->max, domMin0, domMax0);
      }
      if (rescale1) {
        val1 = AIR_AFFINE(range1->min, val1, range1->max, domMin1, domMax1);
      }
      if (AIR_EXISTS(val0) && AIR_EXISTS(val1)) {
        mapIdx0 = airIndexClamp(domMin0, val0, domMax0, mapLen0);
        mapIdx1 = airIndexClamp(domMin1, val1, domMax1, mapLen1);
        entData = mapData + entSize*(mapIdx0 + mapLen0*mapIdx1);
        for (i=0; i<entLen; i++) {
          outInsert(outData, i, mapLup(entData, i));
        }
      } else {
        /* copy non-existant values from input to output */
        for (i=0; i<entLen; i++) {
          outInsert(outData, i, val0 + val1);  /* HEY this is weird */
        }
      }
      inData += 2*inSize;
      outData += outSize;
    }
  }

  return 0;
}
Example #26
0
int
tenGlyphParmCheck(tenGlyphParm *parm,
                  const Nrrd *nten, const Nrrd *npos, const Nrrd *nslc) {
  static const char me[]="tenGlyphParmCheck";
  int duh;
  size_t tenSize[3];
  char stmp[5][AIR_STRLEN_SMALL];

  if (!(parm && nten)) {
    biffAddf(TEN, "%s: got NULL pointer", me);
    return 1;
  }
  if (airEnumValCheck(tenAniso, parm->anisoType)) {
    biffAddf(TEN, "%s: unset (or invalid) anisoType (%d)",
             me, parm->anisoType);
    return 1;
  }
  if (airEnumValCheck(tenAniso, parm->colAnisoType)) {
    biffAddf(TEN, "%s: unset (or invalid) colAnisoType (%d)",
             me, parm->colAnisoType);
    return 1;
  }
  if (!( parm->facetRes >= 3 )) {
    biffAddf(TEN, "%s: facet resolution %d not >= 3", me, parm->facetRes);
    return 1;
  }
  if (!( AIR_IN_OP(tenGlyphTypeUnknown, parm->glyphType,
                   tenGlyphTypeLast) )) {
    biffAddf(TEN, "%s: unset (or invalid) glyphType (%d)",
             me, parm->glyphType);
    return 1;
  }
  if (!( parm->glyphScale > 0)) {
    biffAddf(TEN, "%s: glyphScale must be > 0 (not %g)", me, parm->glyphScale);
    return 1;
  }
  if (parm->nmask) {
    if (npos) {
      biffAddf(TEN, "%s: can't do masking with explicit coordinate list", me);
      return 1;
    }
    if (!( 3 == parm->nmask->dim
           && parm->nmask->axis[0].size == nten->axis[1].size
           && parm->nmask->axis[1].size == nten->axis[2].size
           && parm->nmask->axis[2].size == nten->axis[3].size )) {
      biffAddf(TEN, "%s: mask isn't 3-D or doesn't have sizes (%s,%s,%s)", me,
               airSprintSize_t(stmp[0], nten->axis[1].size),
               airSprintSize_t(stmp[1], nten->axis[2].size),
               airSprintSize_t(stmp[2], nten->axis[3].size));
      return 1;
    }
    if (!(AIR_EXISTS(parm->maskThresh))) {
      biffAddf(TEN, "%s: maskThresh hasn't been set", me);
      return 1;
    }
  }
  if (!( AIR_EXISTS(parm->anisoThresh)
         && AIR_EXISTS(parm->confThresh) )) {
    biffAddf(TEN, "%s: anisoThresh and confThresh haven't both been set", me);
    return 1;
  }
  if (parm->doSlice) {
    if (npos) {
      biffAddf(TEN, "%s: can't do slice with explicit coordinate list", me);
      return 1;
    }
    if (!( parm->sliceAxis <=2 )) {
      biffAddf(TEN, "%s: slice axis %d invalid", me, parm->sliceAxis);
      return 1;
    }
    if (!( parm->slicePos < nten->axis[1+parm->sliceAxis].size )) {
      biffAddf(TEN, "%s: slice pos %s not in valid range [0..%s]", me,
               airSprintSize_t(stmp[0], parm->slicePos),
               airSprintSize_t(stmp[1], nten->axis[1+parm->sliceAxis].size-1));
      return 1;
    }
    if (nslc) {
      if (2 != nslc->dim) {
        biffAddf(TEN, "%s: explicit slice must be 2-D (not %d)",
                 me, nslc->dim);
        return 1;
      }
      tenSize[0] = nten->axis[1].size;
      tenSize[1] = nten->axis[2].size;
      tenSize[2] = nten->axis[3].size;
      for (duh=parm->sliceAxis; duh<2; duh++) {
        tenSize[duh] = tenSize[duh+1];
      }
      if (!( tenSize[0] == nslc->axis[0].size
             && tenSize[1] == nslc->axis[1].size )) {
        biffAddf(TEN, "%s: axis %u slice of %sx%sx%s volume != %sx%s", me,
                 parm->sliceAxis,
                 airSprintSize_t(stmp[0], nten->axis[1].size),
                 airSprintSize_t(stmp[1], nten->axis[2].size),
                 airSprintSize_t(stmp[2], nten->axis[3].size),
                 airSprintSize_t(stmp[3], nslc->axis[0].size),
                 airSprintSize_t(stmp[4], nslc->axis[1].size));
        return 1;
      }
    } else {
      if (airEnumValCheck(tenAniso, parm->sliceAnisoType)) {
        biffAddf(TEN, "%s: unset (or invalid) sliceAnisoType (%d)",
                 me, parm->sliceAnisoType);
        return 1;
      }
    }
  }
  return 0;
}
Example #27
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 #28
0
void
hestGlossary(FILE *f, hestOpt *opt, hestParm *_parm) {
  int i, j, len, maxlen, numOpts;
  char buff[2*AIR_STRLEN_HUGE], tmpS[AIR_STRLEN_HUGE];
  hestParm *parm;

  parm = !_parm ? hestParmNew() : _parm;

  if (_hestPanic(opt, NULL, parm)) {
    /* we can't continue; the opt array is botched */
    parm = !_parm ? hestParmFree(parm) : NULL;
    return;
  }
    
  numOpts = _hestNumOpts(opt);

  maxlen = 0;
  if (numOpts) {
    fprintf(f, "\n");
  }
  for (i=0; i<numOpts; i++) {
    strcpy(buff, "");
    _hestSetBuff(buff, opt + i, parm, AIR_TRUE, AIR_FALSE);
    maxlen = AIR_MAX((int)strlen(buff), maxlen);
  }
  if (parm && parm->respFileEnable) {
    sprintf(buff, "%cfile ...", parm->respFileFlag);
    len = strlen(buff);
    for (j=len; j<maxlen; j++) {
      fprintf(f, " ");
    }
    fprintf(f, "%s = ", buff);
    strcpy(buff, "response file(s) containing command-line arguments");
    _hestPrintStr(f, maxlen + 3, maxlen + 3, parm->columns, buff, AIR_FALSE);
  }
  for (i=0; i<numOpts; i++) {
    strcpy(buff, "");
    _hestSetBuff(buff, opt + i, parm, AIR_TRUE, AIR_FALSE);
    airOneLinify(buff);
    len = strlen(buff);
    for (j=len; j<maxlen; j++) {
      fprintf(f, " ");
    }
    fprintf(f, "%s", buff);
    strcpy(buff, "");
#if 1
    if (opt[i].flag && strchr(opt[i].flag, parm->multiFlagSep)) {
      /* there is a long-form flag as well as short */
      _hestSetBuff(buff, opt + i, parm, AIR_FALSE, AIR_TRUE);
      strcat(buff, " = ");
      fprintf(f, " , ");
    } else {
      /* there is only a short-form flag */
      fprintf(f, " = ");
    }
#else
    fprintf(f, " = ");
#endif
    if (opt[i].info) {
      strcat(buff, opt[i].info);
    }
    if ((opt[i].min || _hestMax(opt[i].max))
        && (!( 2 == opt[i].kind
               && airTypeEnum == opt[i].type 
               && parm->elideSingleEnumType )) 
        && (!( 2 == opt[i].kind
               && airTypeOther == opt[i].type 
               && parm->elideSingleOtherType )) 
        ) {
      /* if there are newlines in the info, then we want to clarify the
         type by printing it on its own line */
      if (opt[i].info && strchr(opt[i].info, '\n')) {
        strcat(buff, "\n ");
      }
      else {
        strcat(buff, " ");
      }
      strcat(buff, "(");
      if (opt[i].min == 0 && _hestMax(opt[i].max) == 1) {
        strcat(buff, "optional\t");
      }
      else {
        if ((int)opt[i].min == _hestMax(opt[i].max) && _hestMax(opt[i].max) > 1) { /* HEY scrutinize casts */
          sprintf(tmpS, "%d\t", _hestMax(opt[i].max));
          strcat(buff, tmpS);
        }
        else if ((int)opt[i].min < _hestMax(opt[i].max)) { /* HEY scrutinize casts */
          if (-1 == opt[i].max) {
            sprintf(tmpS, "%d\tor\tmore\t", opt[i].min);
          }
          else {
            sprintf(tmpS, "%d..%d\t", opt[i].min, _hestMax(opt[i].max));
          }
          strcat(buff, tmpS);
        }
      }
      sprintf(tmpS, "%s%s", 
              (airTypeEnum == opt[i].type
               ? opt[i].enm->name
               : (airTypeOther == opt[i].type
                  ? opt[i].CB->type
                  : airTypeStr[opt[i].type])),
              (_hestMax(opt[i].max) > 1 
               ? (airTypeOther == opt[i].type
                  && 'y' == opt[i].CB->type[airStrlen(opt[i].CB->type)-1]
                  && parm->cleverPluralizeOtherY
                  ? "\bies" 
                  : "s")
               : ""));
      strcat(buff, tmpS);
      strcat(buff, ")");
    }
    /*
    fprintf(stderr, "!%s: parm->elideSingleOtherDefault = %d\n",
            "hestGlossary", parm->elideSingleOtherDefault);
    */
    if (opt[i].dflt 
        && (opt[i].min || _hestMax(opt[i].max))
        && (!( 2 == opt[i].kind
               && (airTypeFloat == opt[i].type || airTypeDouble == opt[i].type)
               && !AIR_EXISTS(airAtod(opt[i].dflt)) 
               && parm->elideSingleNonExistFloatDefault ))
        && (!( (3 == opt[i].kind || 5 == opt[i].kind) 
               && (airTypeFloat == opt[i].type || airTypeDouble == opt[i].type)
               && !AIR_EXISTS(airAtod(opt[i].dflt)) 
               && parm->elideMultipleNonExistFloatDefault ))
        && (!( 2 == opt[i].kind
               && airTypeOther == opt[i].type
               && parm->elideSingleOtherDefault ))
        && (!( 2 == opt[i].kind
               && airTypeString == opt[i].type
               && parm->elideSingleEmptyStringDefault 
               && 0 == airStrlen(opt[i].dflt) ))
        && (!( (3 == opt[i].kind || 5 == opt[i].kind) 
               && airTypeString == opt[i].type
               && parm->elideMultipleEmptyStringDefault 
               && 0 == airStrlen(opt[i].dflt) ))
        ) {
      /* if there are newlines in the info, then we want to clarify the
         default by printing it on its own line */
      if (opt[i].info && strchr(opt[i].info, '\n')) {
        strcat(buff, "\n ");
      }
      else {
        strcat(buff, "; ");
      }
      strcat(buff, "default:\t");
      strcpy(tmpS, opt[i].dflt);
      airStrtrans(tmpS, ' ', '\t');
      strcat(buff, "\"");
      strcat(buff, tmpS);
      strcat(buff, "\"");
    }
    _hestPrintStr(f, maxlen + 3, maxlen + 3, parm->columns, buff, AIR_FALSE);
  }
  parm = !_parm ? hestParmFree(parm) : NULL;

  return;
}
Example #29
0
int
_nrrdHestIterParse(void *ptr, char *str, char err[AIR_STRLEN_HUGE]) {
  char me[]="_nrrdHestIterParse", *nerr;
  Nrrd *nrrd;
  NrrdIter **iterP;
  airArray *mop;
  double val;
  int ret;

  if (!(ptr && str)) {
    sprintf(err, "%s: got NULL pointer", me);
    return 1;
  }
  iterP = (NrrdIter **)ptr;
  mop = airMopNew();
  *iterP = nrrdIterNew();
  airMopAdd(mop, *iterP, (airMopper)nrrdIterNix, airMopOnError);

  /* the challenge here is determining if a given string represents a
     filename or a number.  Obviously there are cases where it could
     be both, so we'll assume its a filename first.  Because: there
     are different ways of writing the same number, such as "3" -->
     "+3", "3.1" --> "3.10", so someone accidently using the file when
     they mean to use the number has easy ways of changing the number
     representation, since these trivial transformations will probably
     not all result in valid filenames. Another problem is that one
     really wants a general robust test to see if a given string is a
     valid number representation AND NOTHING BUT THAT, and sscanf() is
     not that test.  In any case, if there are to be improved smarts
     about this matter, they need to be implemented below and nowhere
     else. */

  nrrd = nrrdNew();
  ret = nrrdLoad(nrrd, str, NULL);
  if (!ret) {
    /* first attempt at nrrdLoad() was SUCCESSFUL */
    nrrdIterSetOwnNrrd(*iterP, nrrd);
  } else {
    /* so it didn't load as a nrrd- if its because fopen() failed,
       then we'll try it as a number.  If its for another reason,
       then we complain */
    nrrdNuke(nrrd);
    if (2 != ret) {
      /* it failed because of something besides the fopen(), so complain */
      nerr = biffGetDone(NRRD);
      airStrcpy(err, AIR_STRLEN_HUGE, nerr);
      airMopError(mop); return 1;
    } else {
      /* fopen() failed, so it probably wasn't meant to be a filename */
      free(biffGetDone(NRRD));
      ret = airSingleSscanf(str, "%lf", &val);
      if (_nrrdLooksLikeANumber(str)
          || (1 == ret && (!AIR_EXISTS(val)
                           || AIR_ABS(AIR_PI - val) < 0.0001))) {
        /* either it patently looks like a number, or,
           it already parsed as a number and it is a special value */
        if (1 == ret) {
          nrrdIterSetValue(*iterP, val);
        } else {
          /* oh, this is bad. */
          fprintf(stderr, "%s: PANIC, is it a number or not?", me);
          exit(1);
        }
      } else {
        /* it doesn't look like a number, but the fopen failed, so
           we'll let it fail again and pass back the error messages */
        if (nrrdLoad(nrrd = nrrdNew(), str, NULL)) {
          nerr = biffGetDone(NRRD);
          airStrcpy(err, AIR_STRLEN_HUGE, nerr);
          airMopError(mop); return 1;
        } else {
          /* what the hell? */
          fprintf(stderr, "%s: PANIC, is it a nrrd or not?", me);
          exit(1);
        }
      }
    }
  }
  airMopAdd(mop, iterP, (airMopper)airSetNull, airMopOnError);
  airMopOkay(mop);
  return 0;
}
Example #30
0
int
hooverContextCheck(hooverContext *ctx) {
    static const char me[]="hooverContextCheck";
    int sxe, sye, sze, minSize, centr;

    if (!ctx) {
        biffAddf(HOOVER, "%s: got NULL pointer", me);
        return 1;
    }
    if (airEnumValCheck(nrrdCenter, ctx->imgCentering)) {
        biffAddf(HOOVER, "%s: pixel centering (%d) invalid",
                 me, ctx->imgCentering);
        return 1;
    }
    centr = (ctx->shape ? ctx->shape->center : ctx->volCentering);
    if (airEnumValCheck(nrrdCenter, centr)) {
        biffAddf(HOOVER, "%s: voxel centering (%d) invalid", me, centr);
        return 1;
    }
    if (limnCameraAspectSet(ctx->cam,
                            ctx->imgSize[0], ctx->imgSize[1], ctx->imgCentering)
            || limnCameraUpdate(ctx->cam)) {
        biffMovef(HOOVER, LIMN, "%s: trouble setting up camera", me);
        return 1;
    }
    if (ctx->shape) {
        if (!ELL_4M_EXISTS(ctx->shape->ItoW)) {
            biffAddf(HOOVER, "%s: given shape doesn't seem to be set", me);
            return 1;
        }
    } else {
        minSize = (nrrdCenterCell == centr ? 1 : 2);
        if (!(ctx->volSize[0] >= minSize
                && ctx->volSize[1] >= minSize
                && ctx->volSize[2] >= minSize)) {
            biffAddf(HOOVER, "%s: volume dimensions (%dx%dx%d) too small", me,
                     ctx->volSize[0], ctx->volSize[1], ctx->volSize[2]);
            return 1;
        }
        sxe = AIR_EXISTS(ctx->volSpacing[0]);
        sye = AIR_EXISTS(ctx->volSpacing[1]);
        sze = AIR_EXISTS(ctx->volSpacing[2]);
        if (!sxe && !sye && !sze) {
            /* none of the incoming spacings existed, we'll go out on a limb
               and assume unit spacing */
            ctx->volSpacing[0] = nrrdDefaultSpacing;
            ctx->volSpacing[1] = ctx->volSpacing[2] = ctx->volSpacing[0];
            fprintf(stderr, "%s: WARNING: assuming spacing %g for all axes\n",
                    me, ctx->volSpacing[0]);
            /* HEY : nrrdDefaultSpacing need not be the same as gageParm's
               defaultSpacing, but we don't know anything about gage here,
               so what else can we do? */
        } else if (sxe && sye && sze) {
            /* all existed */
            if (!(ctx->volSpacing[0] > 0.0
                    && ctx->volSpacing[1] > 0.0
                    && ctx->volSpacing[2] > 0.0)) {
                biffAddf(HOOVER, "%s: volume spacing (%gx%gx%g) invalid", me,
                         ctx->volSpacing[0], ctx->volSpacing[1], ctx->volSpacing[2]);
                return 1;
            }
        } else {
            /* some existed, some didn't */
            biffAddf(HOOVER, "%s: spacings %g, %g, %g don't all exist or not", me,
                     ctx->volSpacing[0], ctx->volSpacing[1], ctx->volSpacing[2]);
            return 1;
        }
    }
    if (!(ctx->imgSize[0] > 0 && ctx->imgSize[1] > 0)) {
        biffAddf(HOOVER, "%s: image dimensions (%dx%d) invalid", me,
                 ctx->imgSize[0], ctx->imgSize[1]);
        return 1;
    }
    if (!(ctx->numThreads >= 1)) {
        biffAddf(HOOVER, "%s: number threads (%d) invalid", me, ctx->numThreads);
        return 1;
    }
    if (!(ctx->numThreads <= HOOVER_THREAD_MAX)) {
        biffAddf(HOOVER, "%s: sorry, number threads (%d) > max (%d)", me,
                 ctx->numThreads, HOOVER_THREAD_MAX);
        return 1;
    }
    if (!ctx->renderBegin) {
        biffAddf(HOOVER, "%s: need a non-NULL begin rendering callback", me);
        return 1;
    }
    if (!ctx->rayBegin) {
        biffAddf(HOOVER, "%s: need a non-NULL begin ray callback", me);
        return 1;
    }
    if (!ctx->threadBegin) {
        biffAddf(HOOVER, "%s: need a non-NULL begin thread callback", me);
        return 1;
    }
    if (!ctx->sample) {
        biffAddf(HOOVER, "%s: need a non-NULL sampler callback function", me);
        return 1;
    }
    if (!ctx->rayEnd) {
        biffAddf(HOOVER, "%s: need a non-NULL end ray callback", me);
        return 1;
    }
    if (!ctx->threadEnd) {
        biffAddf(HOOVER, "%s: need a non-NULL end thread callback", me);
        return 1;
    }
    if (!ctx->renderEnd) {
        biffAddf(HOOVER, "%s: need a non-NULL end render callback", me);
        return 1;
    }

    return 0;
}