Beispiel #1
0
void displayDomains(void)
{
  DomainListItem	*newItem;
  HGUDlpListItem	*item;
  WlzObject		*obj1;
  WlzErrorNum		errNum;

  /* check globals and domain list */
  if((globals.obj == NULL) ||
     (globals.dmnList == NULL) ||
     (HGUDlpListCount(globals.dmnList) <= 0)){
    return;
  }

  /* loop through domains and display the boundlist */
  item = HGUDlpListHead(globals.dmnList);
  while( item ){
    newItem = (DomainListItem *) HGUDlpListEntryGet(globals.dmnList, item);
    if( !newItem->currBound ){
      /* get the section thought the domain */
      if( newItem->obj ){
	if( obj1 = WlzGetSectionFromObject(newItem->obj, globals.wlzViewStr,
					   WLZ_INTERPOLATION_NEAREST,
					   &errNum) ){
	  WlzObject	*tmpBoundary;

	  obj1 = WlzAssignObject(obj1, NULL);
	  tmpBoundary = WlzObjToBoundary(obj1, 1, &errNum);
	  newItem->currBound =
	    WlzAssignObject(tmpBoundary, NULL);
	  WlzFreeObj(obj1);
	}
      }
    }
    /* display it */
    if( newItem->currBound ){
      if( obj1 ){
	if( newItem == globals.currDmnListItem ){
	  DisplayBoundPiece(globals.dpy, globals.win, globals.gc_blue,
			    obj1->domain.b);
	}
	else {
	  DisplayBoundPiece(globals.dpy, globals.win, globals.gc_red,
			    obj1->domain.b);
	}
	WlzFreeObj(obj1);
      }
    }
    item = HGUDlpListNext(globals.dmnList, item);
  }  

  return;
}
/*!
* \return	New Woolz object without holes or NULL on error.
* \ingroup	WlzDomainOps
* \brief	Fills the holes in the given object's domain (which are by
* 		definition not connected to the outside). When the given
* 		object's domain has more than one component part, the
* 		object should first be labeled, this function should then be
* 		called for each of the labeled parts and then the union of
* 		the filled domains should be formed.
* \param	srcObj			Given 3D domain object.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzObject 			*WlzDomainFill3D(
  				  WlzObject *srcObj,
    				  WlzErrorNum *dstErr)
{
  int		nPln = 0;
  WlzObject	*bndObj = NULL,
  		*filObj = NULL,
  		*gvnObj = NULL,
		*sedObj = NULL,
		*shlObj = NULL;
  WlzPixelV	zeroV;
  WlzValues 	nullVal;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  nullVal.core = NULL;
  zeroV.type = WLZ_GREY_UBYTE;
  zeroV.v.ubv = 0;
  if(srcObj == NULL)
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else if(srcObj->type != WLZ_3D_DOMAINOBJ)
  {
    errNum = WLZ_ERR_OBJECT_TYPE;
  }
  else if(srcObj->domain.core == NULL)
  {
    errNum = WLZ_ERR_DOMAIN_NULL;
  }
  else
  {
    gvnObj = WlzMakeMain(srcObj->type, srcObj->domain, nullVal,
    		         NULL, NULL, &errNum);
  }
  /* Create a then shell 1 voxel thick just inside the given objects's
   * domain. */
  if(errNum == WLZ_ERR_NONE)
  {
    WlzObject	*difObj = NULL;

    difObj = WlzAssignObject(
	     WlzBoundaryDomain(gvnObj, &errNum), NULL);
    if(errNum == WLZ_ERR_NONE)
    {
      WlzIBox3	clipBox;

      /* Clip the dilated shell domain to make sure it stays within the
       * bounding box of the given object then all planes will align. */
      clipBox.xMin = gvnObj->domain.p->kol1;
      clipBox.yMin = gvnObj->domain.p->line1;
      clipBox.zMin = gvnObj->domain.p->plane1;
      clipBox.xMax = gvnObj->domain.p->lastkl;
      clipBox.yMax = gvnObj->domain.p->lastln;
      clipBox.zMax = gvnObj->domain.p->lastpl;
      shlObj = WlzAssignObject(
	       WlzClipObjToBox3D(difObj, clipBox, &errNum), NULL);
    }
    (void )WlzFreeObj(difObj);
  }
  /* Make sure that the bounding box of the thin shell domain fits it and
   * that it's first and last planes have interrvals. */
  if(errNum == WLZ_ERR_NONE)
  {
    errNum = WlzStandardPlaneDomain(shlObj->domain.p, NULL);
  }
  /* Create a value table for the shell object with values set to zero. */
  if(errNum == WLZ_ERR_NONE)
  {
    WlzValues	val;
    WlzObjectType tType;

    tType = WlzGreyTableType(WLZ_GREY_TAB_INTL, WLZ_GREY_UBYTE, NULL);
    val.vox = WlzMakeVoxelValueTb(WLZ_VOXELVALUETABLE_GREY,
				  shlObj->domain.p->plane1,
				  shlObj->domain.p->lastpl,
				  zeroV, NULL, &errNum);
    if(errNum == WLZ_ERR_NONE)
    {
      int	p;

      nPln = shlObj->domain.p->lastpl - shlObj->domain.p->plane1 + 1;
      shlObj->values = WlzAssignValues(val, NULL);
#ifdef _OPENMP
#pragma omp parallel for shared(shlObj)
#endif
      for(p = 0; p < nPln; ++p)
      {
	if(errNum == WLZ_ERR_NONE)
	{
	  WlzDomain dom2;
	  WlzErrorNum errNum2;

	  dom2 = shlObj->domain.p->domains[p];
	  if(dom2.core)
	  {
	    WlzValues val2;
	    WlzObject *shlObj2;
	    shlObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, dom2, nullVal, NULL, NULL,
				&errNum2);
	    if(errNum2 == WLZ_ERR_NONE)
	    {
	      val2.i = WlzMakeIntervalValues(tType, shlObj2, zeroV, &errNum2);
	      /* WlzMakeIntervalValues() sets all values to zero. */
	    }
	    if(errNum2 == WLZ_ERR_NONE)                          
	    {
	      shlObj->values.vox->values[p] = WlzAssignValues(val2, NULL);
	    }
	    (void )WlzFreeObj(shlObj2);
	    if(errNum2 == WLZ_ERR_NONE)
	    {
#ifdef _OPENMP
#pragma omp critical
	      {
#endif
		if((errNum == WLZ_ERR_NONE) && (errNum2 != WLZ_ERR_NONE))
		{
		  errNum = errNum2;
		}
#ifdef _OPENMP
	      }
#endif
	    }
	  }
	}
      }
    }
  }
  /* Compute the (plane-wise) boundary list for the given object. */
  if(errNum == WLZ_ERR_NONE)
  {
    bndObj = WlzObjToBoundary(gvnObj, 0, &errNum);
  }
  /* Sweep down through the boundary object setting the values of
   * those voxels in the shell object to a non zero value when they
   * correspond to top level boundaries. */
  if(errNum == WLZ_ERR_NONE)
  {
    int		p;

#ifdef _OPENMP
#pragma omp parallel for shared(bndObj,shlObj)
#endif
    for(p = 0; p < nPln; ++p)
    {
      if(errNum == WLZ_ERR_NONE)
      {
	WlzDomain bDom2;

	bDom2 = bndObj->domain.p->domains[p];
	if(bDom2.core)
	{
	  WlzDomain iDom2;
	  WlzValues iVal2;
	  WlzObject *iObj2 = NULL;
	  WlzGreyValueWSpace *gVWSp = NULL;
	  WlzErrorNum errNum2 = WLZ_ERR_NONE;

	  iDom2 = shlObj->domain.p->domains[p];
	  iVal2 = shlObj->values.vox->values[p];
	  iObj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ, iDom2, iVal2, NULL, NULL,
			      &errNum2);
	  if(errNum == WLZ_ERR_NONE)
	  {
	    gVWSp = WlzGreyValueMakeWSp(iObj2, &errNum2);
	  }
	  if(errNum2 == WLZ_ERR_NONE)
	  {
	    WlzBoundList *bnd,
			 *bnd2;

	    bnd2 = bDom2.b;
	    for(bnd = bnd2; bnd != NULL; bnd = bnd->next)
	    {
	      if(bnd->poly != NULL)
	      {
		WlzPolygonDomain *ply;

		ply = bnd->poly;
		if(ply)
		{
		  int	i;
		  WlzIVertex2 *vtx;

		  vtx = ply->vtx;
		  for(i = 0; i < ply->nvertices; ++i)
		  {
		    WlzGreyValueGet(gVWSp, 0, vtx[i].vtY, vtx[i].vtX);
		    *(gVWSp->gPtr[0].ubp) = 255;
		  }
		}
	      }
	    }
	  }
	  else
	  {
#ifdef _OPENMP
#pragma omp critical
	    {
#endif
	      if(errNum == WLZ_ERR_NONE)
	      {
		errNum = errNum2;
	      }
#ifdef _OPENMP
	    }
#endif
	  }
	  (void )WlzFreeObj(iObj2);
	  WlzGreyValueFreeWSp(gVWSp);
	}
      }
    }
  }
  /* Threshold the shell object, throwing away all but where the voxels
   * are set to create a seed domain. Then remove the value table from
   * the shell object and free it as it's no longer needed. */
  if(errNum == WLZ_ERR_NONE)
  {
    WlzObject	*tObj = NULL;
    WlzPixelV	tV;

    tV.type = WLZ_GREY_UBYTE;
    tV.v.ubv = 1;
    tObj = WlzAssignObject(
    	   WlzThreshold(shlObj, tV, WLZ_THRESH_HIGH, &errNum), NULL);
    if(errNum == WLZ_ERR_NONE)
    {
      sedObj = WlzAssignObject(
      	       WlzMakeMain(tObj->type, tObj->domain, nullVal,
			   NULL, NULL, &errNum), NULL);
    }
    (void )WlzFreeObj(tObj); tObj = NULL;
    if(errNum == WLZ_ERR_NONE)
    {
      tObj = WlzAssignObject(
             WlzMakeMain(shlObj->type, shlObj->domain, nullVal,
			 NULL, NULL, &errNum), NULL);
    }
    (void )WlzFreeObj(shlObj); shlObj = NULL;
    if(errNum == WLZ_ERR_NONE)
    {
      shlObj = tObj;
      tObj = NULL;
    }
    (void )WlzFreeObj(tObj);
#ifdef WLZ_DOMOMAINFILL3D_DEBUG
    {
      FILE	*fP;
      fP = fopen("debug-shlObj-00.wlz", "w");
      (void )WlzWriteObj(fP, shlObj);
      (void )fclose(fP);
    }
#endif
  }
  /* Label the shell domain using 26-connectivity in 3D and then
   * keep only those component objects which intersect the seed domain.
   * Then free the shell and seed domains replacing the shell domain
   * with the union of the intersecting labeled component objects.
   * Finaly free the intersecting component objects, keeping only the
   * new shell domain. */
  if(errNum == WLZ_ERR_NONE)
  {
    int		i,
		j,
    		nCSObj = 0;
    WlzIBox3	bBox;
    WlzObject	**csObj = NULL;

    bBox = WlzBoundingBox3I(shlObj, &errNum);
    if(errNum == WLZ_ERR_NONE)      
    {
      int	maxCSObj;

      maxCSObj = ((bBox.xMax - bBox.xMin + 1) *
      		  (bBox.yMax - bBox.yMin + 1) *
      		  (bBox.zMax - bBox.zMin + 1)) / 8;
      if(maxCSObj < 8)
      {
        maxCSObj = 8;
      }
      errNum = WlzLabel(shlObj, &nCSObj, &csObj, maxCSObj, 0,
			WLZ_26_CONNECTED);
    }
    if(errNum == WLZ_ERR_NONE)
    {
      for(i = 0; i < nCSObj; ++i)
      {
        if(!WlzHasIntersection(csObj[i], sedObj, &errNum))
	{
	  (void )WlzFreeObj(csObj[i]);
	  csObj[i] = NULL;
	}
      }
    }
    if(errNum == WLZ_ERR_NONE)
    {
      /* Squeeze out any NULL objects reseting their number.*/
      for(i = 0, j = 0; i < nCSObj; ++i)
      {
        if(csObj[i])
	{
	  csObj[j++] = csObj[i];
	}
      }
      nCSObj = j;
    }
    if(errNum == WLZ_ERR_NONE)
    {
      WlzObject	*iObj = NULL,
      		*uObj = NULL;

      uObj = WlzAssignObject(
      	     WlzUnionN(nCSObj, csObj, 0, &errNum), NULL);
      iObj = WlzAssignObject(
               WlzIntersect2(uObj, shlObj, &errNum),  NULL);
      (void )WlzFreeObj(uObj);
      (void )WlzFreeObj(shlObj);
      shlObj = iObj;
#ifdef WLZ_DOMOMAINFILL3D_DEBUG
      {
	FILE	*fP;
	fP = fopen("debug-shlObj-01.wlz", "w");
	(void )WlzWriteObj(fP, shlObj);
	(void )fclose(fP);
      }
#endif
    }
    if(csObj)
    {
      for(i = 0; i < nCSObj; ++i)
      {
        (void )WlzFreeObj(csObj[i]);
      }
      (void )AlcFree(csObj);
    }
  }
  /* Sweep down through the boundary lists again creating new boundary lists
   * which do not have boundaries that do not intersect the new shell domain.
   * Then create a new filled object from these boundary lists. */
  if(errNum == WLZ_ERR_NONE)
  {
    int		p,
    		nPlnFil;
    WlzDomain	filDom;

    nPlnFil = shlObj->domain.p->lastpl - shlObj->domain.p->plane1 + 1;
    filDom.p = WlzMakePlaneDomain(WLZ_PLANEDOMAIN_DOMAIN, 
		shlObj->domain.p->plane1, shlObj->domain.p->lastpl,
                shlObj->domain.p->line1, shlObj->domain.p->lastln,
                shlObj->domain.p->kol1, shlObj->domain.p->lastkl,
		&errNum);
#ifdef _OPENMP
#pragma omp parallel for shared(bndObj,shlObj)
#endif
    for(p = 0; p < nPlnFil; ++p)
    {
      if(errNum == WLZ_ERR_NONE)
      {
	WlzDomain bDom2;
	
	bDom2 = bndObj->domain.p->domains[p];
	if(bDom2.core)
	{
	  WlzDomain 	sDom2;
	  WlzObject	*fObj2 = NULL;
	  WlzBoundList  *newBnd = NULL;
	  WlzErrorNum	errNum2 = WLZ_ERR_NONE;

	  sDom2 = shlObj->domain.p->domains[p];
	  if(sDom2.core)
	  {
	    newBnd = WlzDomFill3DDoBound2D(bDom2.b, sDom2, &errNum2);
	    if(newBnd != NULL)
	    {
	      fObj2 = WlzBoundToObj(newBnd, WLZ_SIMPLE_FILL, &errNum2);
	      (void )WlzFreeBoundList(newBnd);
	    }
	    if(errNum2 == WLZ_ERR_NONE)
	    {
	      if(fObj2)
	      {
		filDom.p->domains[p] = WlzAssignDomain(fObj2->domain, NULL);
	      }
	    }
	    else
	    {
#ifdef _OPENMP
#pragma omp critical
	      {
#endif
		if(errNum == WLZ_ERR_NONE)
		{
		  errNum = errNum2;
		}
#ifdef _OPENMP
	      }
#endif
	    }
	    (void )WlzFreeObj(fObj2);
	  }
	}
      }
    }
    if(errNum == WLZ_ERR_NONE)
    {
      errNum = WlzStandardPlaneDomain(filDom.p, NULL);
    }
    if(errNum == WLZ_ERR_NONE)
    {
      WlzObject	*tObj0 = NULL,
      		*tObj1 = NULL;

      /* Put back any isolated voxels this function has removed. */
      tObj0 = WlzAssignObject(
              WlzMakeMain(srcObj->type, filDom, nullVal,
      			  NULL, NULL, &errNum), NULL);
      if(errNum == WLZ_ERR_NONE)
      {
        tObj1 = WlzUnion2(gvnObj, tObj0, &errNum);
      }
      if(errNum == WLZ_ERR_NONE)
      {
	filObj = WlzMakeMain(tObj1->type, tObj1->domain, nullVal,
			     NULL, NULL, &errNum);
      }
      (void )WlzFreeObj(tObj0);
      (void )WlzFreeObj(tObj1);
    }
  }
  (void )WlzFreeObj(bndObj);
  (void )WlzFreeObj(gvnObj);
  (void )WlzFreeObj(shlObj);
  (void )WlzFreeObj(sedObj);
  if((errNum != WLZ_ERR_NONE) && (filObj != NULL))
  {
    (void )WlzFreeObj(filObj);
    filObj = NULL;
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(filObj);
}
Beispiel #3
0
/*!
* \return	void
* \brief	Outputs the mesh and displaced mesh of the given mesh
*		transform as Postscript to the standard error output.
* \param	mObj			Given mesh transform object.
* \param	sObj			Source object.
* \param	dilObj			Dilated object.
* \param	outObj			Transformed object.
*/
static void	WlzCMeshOutputPS(WlzObject *mObj,
				 WlzObject *sObj, WlzObject *dilObj,
				 WlzObject *outObj)
{
  int		idE,
  		idN,
		useElm;
  double	scale;
  double	*dsp;
  WlzDVertex2	pos,
  		offset;
  WlzDVertex2	elmVx[3];
  WlzDBox2	bBox;
  WlzCMeshNod2D	*nod;
  WlzCMeshElm2D *elm;
  WlzCMesh2D	*mesh;
  WlzIndexedValues *ixv;
  WlzObject	*bObj = NULL;
  char		buf[100];

  (void )fprintf(stderr, "%%!\n"
			 "/Times-Courier findfont\n"
			 "1 scalefont\n"
			 "setfont\n"
  			 "1 setlinecap\n"
			 "1 setlinejoin\n"
			 "0.01 setlinewidth\n");
  if((mObj != NULL) && (mObj->type == WLZ_CMESH_2D) &&
     ((mesh = mObj->domain.cm2) != NULL) &&
     ((ixv = mObj->values.x) != NULL))
  {
    /* Compute the bounding box of the mesh transform. */
    bBox.xMin = bBox.yMin = DBL_MAX;
    bBox.xMax = bBox.yMax = DBL_MIN;
    for(idN = 0; idN < mesh->res.nod.maxEnt; ++idN)
    {
      nod = (WlzCMeshNod2D *)AlcVectorItemGet(mesh->res.nod.vec, idN);
      if(nod->idx >= 0)
      {
	if(nod->pos.vtX < bBox.xMin)
	{
	  bBox.xMin = nod->pos.vtX;
	}
	else if(nod->pos.vtX > bBox.xMax)
	{
	  bBox.xMax = nod->pos.vtX;
	}
	if(nod->pos.vtY < bBox.yMin)
	{
	  bBox.yMin = nod->pos.vtY;
	}
	else if(nod->pos.vtY > bBox.yMax)
	{
	  bBox.yMax = nod->pos.vtY;
	}
        dsp = (double *)WlzIndexedValueGet(ixv, idN);
	pos.vtX = nod->pos.vtX + dsp[0];
	pos.vtY = nod->pos.vtY + dsp[1];
	if(pos.vtX < bBox.xMin)
	{
	  bBox.xMin = pos.vtX;
	}
	else if(pos.vtX > bBox.xMax)
	{
	  bBox.xMax = pos.vtX;
	}
	if(pos.vtY < bBox.yMin)
	{
	  bBox.yMin = pos.vtY;
	}
	else if(pos.vtY > bBox.yMax)
	{
	  bBox.yMax = pos.vtY;
	}
      }
    }
    if(((pos.vtX = fabs(bBox.xMax - bBox.xMin)) > 1.0) &&
       ((pos.vtY = fabs(bBox.yMax - bBox.yMin)) > 1.0))
    {
      /* Compute scale and offset for an A4 page. */
      if((4.0 * pos.vtX) > (3.0 * pos.vtY))
      {
        scale = 500.0 / (bBox.xMax - bBox.xMin);
      }
      else
      {
        scale = 700.0 / (bBox.yMax - bBox.yMin);
      }
      offset.vtX = (bBox.xMin * scale) - 50;
      offset.vtY = (bBox.yMin * -scale) - 750;
      (void )fprintf(stderr, "255 0 0 setrgbcolor\n");
      for(idE = 0; idE < mesh->res.elm.maxEnt; ++idE)
      {
        elm = (WlzCMeshElm2D *)AlcVectorItemGet(mesh->res.elm.vec, idE);
	if(elm->idx >= 0)
	{
	  for(idN = 0; idN < 3; ++idN)
	  {
	    pos = elm->edu[idN].nod->pos;
	    elmVx[idN].vtX = (pos.vtX * scale) - offset.vtX;
	    elmVx[idN].vtY = (pos.vtY * -scale) - offset.vtY;
	  }
	  (void )fprintf(stderr,
			 "%g %g moveto "
			 "%g %g lineto "
			 "%g %g lineto "
			 "%g %g lineto "
			 "stroke\n",
			 elmVx[0].vtX, elmVx[0].vtY,
			 elmVx[1].vtX, elmVx[1].vtY,
			 elmVx[2].vtX, elmVx[2].vtY,
			 elmVx[0].vtX, elmVx[0].vtY);
	  WLZ_VTX_2_ADD3(pos, elmVx[0], elmVx[1], elmVx[2]);
	  WLZ_VTX_2_SCALE(pos, pos, 0.333333);
	  (void )sprintf(buf, "%d", elm->idx);
	  (void )fprintf(stderr,
			 "%g %g moveto "
			 "(%s) show\n",
			 pos.vtX, pos.vtY,
			 buf);
	}
      }
      (void )fprintf(stderr, "0 0 255 setrgbcolor\n");
      for(idE = 0; idE < mesh->res.elm.maxEnt; ++idE)
      {
        elm = (WlzCMeshElm2D *)AlcVectorItemGet(mesh->res.elm.vec, idE);
	if(elm->idx >= 0)
	{
	  /* Display only those elements that have all nodes inside the
	   * domain.  
	  useElm = ((elm->edg[0].nod->flags | elm->edg[1].nod->flags |
	             elm->edg[2].nod->flags) &
		    WLZ_CMESH_NOD_FLAG_OUTSIDE) == 0;
	  */
	  useElm = 1;
	  if(useElm)
	  {
	    for(idN = 0; idN < 3; ++idN)
	    {
	      pos = elm->edu[idN].nod->pos;
	      dsp = (double *)WlzIndexedValueGet(ixv, elm->edu[idN].nod->idx);
	      pos.vtX += dsp[0];
	      pos.vtY += dsp[1];
	      elmVx[idN].vtX = (pos.vtX * scale) - offset.vtX;
	      elmVx[idN].vtY = (pos.vtY * -scale) - offset.vtY;
	    }
	    (void )fprintf(stderr,
			   "%g %g moveto "
			   "%g %g lineto "
			   "%g %g lineto "
			   "%g %g lineto "
			   "stroke\n",
			   elmVx[0].vtX, elmVx[0].vtY,
			   elmVx[1].vtX, elmVx[1].vtY,
			   elmVx[2].vtX, elmVx[2].vtY,
			   elmVx[0].vtX, elmVx[0].vtY);
	    WLZ_VTX_2_ADD3(pos, elmVx[0], elmVx[1], elmVx[2]);
	    WLZ_VTX_2_SCALE(pos, pos, 0.333333);
	    (void )sprintf(buf, "%d", elm->idx);
	    (void )fprintf(stderr,
	    		   "%g %g moveto "
			   "(%s) show\n",
			   pos.vtX, pos.vtY,
			   buf);
	  }
	}
      }
      (void )fprintf(stderr, "0 255 0 setrgbcolor\n");
      if((bObj = WlzObjToBoundary(sObj, 1, NULL)) != NULL)
      {
        WlzBndOutputPS(bObj->domain.b, scale, offset);
      }
      (void )fprintf(stderr, "0 255 255 setrgbcolor\n");
      if((bObj = WlzObjToBoundary(dilObj, 1, NULL)) != NULL)
      {
        WlzBndOutputPS(bObj->domain.b, scale, offset);
      }
      (void )fprintf(stderr, "127 0 127 setrgbcolor\n");
      if((bObj = WlzObjToBoundary(outObj, 1, NULL)) != NULL)
      {
        WlzBndOutputPS(bObj->domain.b, scale, offset);
      }
      (void )fprintf(stderr, "showpage\n");
    }
  }
}
Beispiel #4
0
void setup_ref_display_list_cb(
Widget	w,
XtPointer	client_data,
XtPointer	call_data)
{

  WlzPlaneDomain	*planedmn;
  WlzThreeDViewStruct	*viewStr;
  WlzErrorNum		errNum=WLZ_ERR_NONE;

  if( globals.obj == NULL || globals.obj->type != WLZ_3D_DOMAINOBJ ||
     globals.ref_display_list == 0){
    return;
  }
  /* create a new display list */
  glDeleteLists(globals.ref_display_list, 1);
  globals.ref_display_list = glGenLists( (GLsizei) 1 );

  planedmn = globals.obj->domain.p;

  /* create the reference object 3D display  DisplayList */
  glNewList( globals.ref_display_list, GL_COMPILE );

  glBegin(GL_LINES);
  glColor3f(1.0, 0.0, 0.0);
  glIndexi( (int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 1.0, 0.0, 0.0) );
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->lastpl);

  glColor3f(0.0, 1.0, 0.0);
  glIndexi( (int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 0.0, 1.0, 0.0) );
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->lastpl);

  glColor3f(0.0, 0.0, 1.0);
  glIndexi( (int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 0.0, 0.0, 1.0) );
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->kol1, planedmn->lastln, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->line1, planedmn->lastpl);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->plane1);
  glVertex3i(planedmn->lastkl, planedmn->lastln, planedmn->lastpl);
  glEnd();

  if( globals.fb_obj && (globals.fb_obj->type == WLZ_3D_DOMAINOBJ) ){
    WlzObject		*obj1, *boundobj;
    WlzValues		values;
    int			z, step;

    /* establish the step size */
    planedmn = globals.fb_obj->domain.p;
    step = (planedmn->lastkl - planedmn->kol1) / 6;
    z = (planedmn->lastln - planedmn->line1) / 6;
    step = WLZ_MIN(step, z);
    z = (planedmn->lastpl - planedmn->plane1) / 6;
    step = WLZ_MIN(step, z);

    /* set up const z boundaries */
    glColor3f(1.0, 1.0, 1.0);
    glIndexi((int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 1.0, 1.0, 1.0));
    (void) glLineWidth( (GLfloat) 2.0 );
    for(z=planedmn->plane1+step/2; z <= planedmn->lastpl; z += step)
    {
      values.core = NULL;
      obj1 = WlzMakeMain(WLZ_2D_DOMAINOBJ,
			 planedmn->domains[z - planedmn->plane1],
			 values, NULL, NULL, NULL);
      if( obj1->domain.core != NULL )
      {
	boundobj = WlzObjToBoundary(obj1, 1, &errNum);
	if( boundobj != NULL )
	{
	  MAOpenGLDisplayBoundList(boundobj->domain.b, (float) z );
	  WlzFreeObj( boundobj );
	}
	if( errNum != WLZ_ERR_NONE ){
	  break;
	}
      }
      WlzFreeObj( obj1 );
    }
    (void) glLineWidth( (GLfloat) 1.0 );

    /* set up const y boundaries */
    if( errNum == WLZ_ERR_NONE ){
      glColor3f(1.0, 1.0, 0.0);
      glIndexi((int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 1.0, 1.0, 0.0));
      if((viewStr = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum))){
	viewStr->theta = WLZ_M_PI / 2.0;
	viewStr->phi = WLZ_M_PI / 2.0;
	viewStr->dist = planedmn->line1 - step/2;
	errNum = WlzInit3DViewStruct(viewStr, globals.fb_obj);
	for(z=viewStr->dist+step; (errNum == WLZ_ERR_NONE) && (z <= planedmn->lastln);
	    z += step)
	{
	  Wlz3DSectionIncrementDistance(viewStr, (double) step);
	  if((obj1 = WlzGetSectionFromObject(globals.fb_obj, viewStr,
					     WLZ_INTERPOLATION_NEAREST,
					     &errNum))){
	    obj1 = WlzAssignObject(obj1, NULL);
	    boundobj = WlzObjToBoundary(obj1, 1, &errNum);
	    if( boundobj != NULL )
	    {
	      /* convert boundary coordinates to voxel coordinates */
	      Wlz3DSectionTransformYBound(boundobj->domain.b, viewStr);
	      MAOpenGLDisplayYBoundList(boundobj->domain.b, (float) z);
	      WlzFreeObj( boundobj );
	    }
	    WlzFreeObj( obj1 );
	  }
	}
	WlzFree3DViewStruct(viewStr);
      }
    }

    /* set up const x boundaries */
    if( errNum == WLZ_ERR_NONE ){
      glIndexi((int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 1.0, 1.0, 0.0));
      glColor3f(1.0, 1.0, 0.0);
      if((viewStr = WlzMake3DViewStruct(WLZ_3D_VIEW_STRUCT, &errNum))){
	viewStr->theta = 0.0;
	viewStr->phi = WLZ_M_PI / 2.0;
	viewStr->dist = planedmn->kol1 - step/2;
	errNum = WlzInit3DViewStruct(viewStr, globals.fb_obj);
	for(z=viewStr->dist+step; (errNum == WLZ_ERR_NONE) && (z <= planedmn->lastkl);
	    z += step)
	{
	  Wlz3DSectionIncrementDistance(viewStr, (double) step);
	  if((obj1 = WlzGetSectionFromObject(globals.fb_obj, viewStr,
					     WLZ_INTERPOLATION_NEAREST,
					     &errNum))){
	    obj1 = WlzAssignObject(obj1, NULL);
	    boundobj = WlzObjToBoundary(obj1, 1, &errNum);
	    if( boundobj != NULL )
	    {
	      /* convert boundary coordinates to voxel coordinates */
	      Wlz3DSectionTransformXBound(boundobj->domain.b, viewStr);
	      MAOpenGLDisplayXBoundList(boundobj->domain.b, (float) z);
	      WlzFreeObj( boundobj );
	    }
	    WlzFreeObj( obj1 );
	  }
	}
	WlzFree3DViewStruct(viewStr);
      }
    }
  }

  if( errNum == WLZ_ERR_NONE ){
    glIndexi( (int) HGU_XGetColorPixel(globals.dpy, globals.cmap, 1.0, 1.0, 1.0) );
    glColor3f(1.0, 1.0, 1.0);
    glEndList();

    WLZ_VTX_3_SET(globals.bbox_vtx, planedmn->kol1 - 2.0,
		  planedmn->line1 - 2.0, planedmn->plane1 - 2.0);
    WLZ_VTX_3_SET(globals.bbox_size,
		  planedmn->lastkl - planedmn->kol1 + 4.0,
		  planedmn->lastln - planedmn->line1 + 4.0,
		  planedmn->lastpl - planedmn->plane1 + 4.0);
    glFogf(GL_FOG_DENSITY, 0.25/globals.bbox_size.vtX);
    MAOpenGLDrawScene( globals.canvas );
  }
  else {
    MAPaintReportWlzError(globals.topl, "setup_ref_display_list_cb", errNum);
  }

  return;
}
Beispiel #5
0
int WlzEdgeVertices(
  WlzObject	*obj,
  WlzDVertex3	**vtxs,
  WlzErrorNum	*dstErr)
{
  int		numVtxs = 0, n;
  WlzDVertex3	*rtnVtxs=NULL, *tmpVtxs;
  WlzErrorNum	errNum=WLZ_ERR_NONE;
  WlzObject	*obj1, *obj2;
  int		i, j;
  WlzValues	values;
  WlzPlaneDomain	*planedmn;

  /* check object */
  if( obj == NULL ){
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else {
    switch( obj->type ){
    case WLZ_2D_DOMAINOBJ:
      if((obj1 = WlzObjToBoundary(obj, 1, &errNum)) != NULL){
	numVtxs = WlzEdgeVerticesBound(obj1->domain.b, &rtnVtxs,
				       0, &errNum);
	WlzFreeObj(obj1);
      }
      break;

    case WLZ_3D_DOMAINOBJ:
      if( obj->domain.core == NULL){
	errNum = WLZ_ERR_DOMAIN_NULL;
      }
      else {
	switch( obj->domain.core->type ){
	case WLZ_PLANEDOMAIN_DOMAIN:
	  planedmn = obj->domain.p;
	  values.core = NULL;
	  for(i=planedmn->plane1; i <= planedmn->lastpl; i++){
	    if( planedmn->domains[i-planedmn->plane1].core ){
	      obj2 = WlzMakeMain(WLZ_2D_DOMAINOBJ,
				 planedmn->domains[i-planedmn->plane1],
				 values, NULL, NULL, NULL);
	      if( (n = WlzEdgeVertices(obj2, &tmpVtxs, &errNum)) > 0){
		if( numVtxs > 0 ){
		  rtnVtxs = AlcRealloc(rtnVtxs,
				       sizeof(WlzDVertex3)*(numVtxs+n));
		}
		else {
		  rtnVtxs = AlcMalloc(sizeof(WlzDVertex3)*n);
		}
		for(j=0; j < n; j++){
		  tmpVtxs[j].vtZ = i;
		  rtnVtxs[numVtxs+j] = tmpVtxs[j];
		}
		AlcFree(tmpVtxs);
		numVtxs += n;
	      }
	      WlzFreeObj(obj2);
	    }
	  }
	  break;

	case WLZ_PLANEDOMAIN_POLYGON:
	case WLZ_PLANEDOMAIN_BOUNDLIST:
	  break;

	case WLZ_EMPTY_DOMAIN:
	  if( dstErr ){
	    *dstErr = errNum;
	  }
	  return numVtxs;

	default:
	  errNum = WLZ_ERR_DOMAIN_TYPE;
	}
      }
      break;

    case WLZ_2D_POLYGON:
      numVtxs = WlzEdgeVerticesPoly(obj->domain.poly, &rtnVtxs, 0, &errNum);
      break;

    case WLZ_BOUNDLIST:
      numVtxs = WlzEdgeVerticesBound(obj->domain.b, &rtnVtxs, 0, &errNum);
      break;

    case WLZ_EMPTY_OBJ:
      if( dstErr ){
	*dstErr = errNum;
      }
      return numVtxs;

    default:
      errNum = WLZ_ERR_OBJECT_TYPE;
    }
  }

  if( dstErr ){
    *dstErr = errNum;
  }
  *vtxs = rtnVtxs;
  return numVtxs;
}
Beispiel #6
0
int		main(int argc, char *argv[])
{
  int		ok,
		bnd = 0,
  		con,
  		option,
		usage = 0;
  char		*inFileStr,
  		*forFileStr,
  		*refFileStr,
		*outFileStr;
  double	dParam = 10.0;
  FILE		*fP = NULL;
  WlzObject	*tObj0,
  		*tObj1,
		*forObj = NULL,
		*refObj = NULL,
		*dstObj = NULL;
  WlzDistanceType dFn;
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  const char	*errMsgStr;
  static char	optList[] = "bhd:f:p:o:";
  const char    fileStrDef[] = "-";
  const WlzConnectType defDFn = WLZ_OCTAGONAL_DISTANCE;

  /* Parse the argument list and check for input files. */
  opterr = 0;
  inFileStr = (char *)fileStrDef;
  forFileStr = (char *)fileStrDef;
  outFileStr = (char *)fileStrDef;
  dFn = defDFn;
  while((option = getopt(argc, argv, optList)) != EOF)
  {
    switch(option)
    {
      case 'b':
        bnd = 1;
	break;
      case 'd':
	if(sscanf(optarg, "%d", &con) != 1)
	{
	  usage = 1;
	}
	else
	{
	  switch(con)
	  {
	    case 0:
	      dFn = WLZ_EUCLIDEAN_DISTANCE;
	      break;
	    case 1:
	      dFn = WLZ_OCTAGONAL_DISTANCE;
	      break;
	    case 2:
	      dFn = WLZ_APX_EUCLIDEAN_DISTANCE;
	      break;
	    case 4:
	      dFn = WLZ_4_DISTANCE;
	      break;
	    case 6:
	      dFn = WLZ_6_DISTANCE;
	      break;
	    case 8:
	      dFn = WLZ_8_DISTANCE;
	      break;
	    case 18:
	      dFn = WLZ_18_DISTANCE;
	      break;
	    case 26:
	      dFn = WLZ_26_DISTANCE;
	      break;
	    default:
	      usage = 1;
	      break;
	  }
	}
	break;
      case 'f':
	forFileStr = optarg;
	break;
      case 'p':
	if(sscanf(optarg, "%lg", &dParam) != 1)
	{
	  usage = 1;
	}
	break;
      case 'o':
	outFileStr = optarg;
	break;
      case 'h':
      default:
	usage = 1;
	break;
    }
  }
  ok = !usage;
  if(ok && (optind < argc))
  {
    if((optind + 1) != argc)
    {
      usage = 1;
      ok = 0;
    }
    else
    {
      refFileStr = argv[optind];
    }
  }
  /* Read the reference object. */
  if(ok)
  {
    if((refFileStr == NULL) ||
       (*refFileStr == '\0') ||
       ((fP = (strcmp(refFileStr, "-")?
              fopen(refFileStr, "r"): stdin)) == NULL) ||
       ((refObj = WlzAssignObject(WlzReadObj(fP, &errNum), NULL)) == NULL))
    {
      ok = 0;
      (void )fprintf(stderr,
                     "%s: Failed to read reference object from file %s.\n",
                     argv[0], refFileStr);
    }
    if(fP && strcmp(refFileStr, "-"))
    {
      (void )fclose(fP); fP = NULL;
    }
  }
  /* Read the foreground object. */
  if(ok)
  {
    if((forFileStr == NULL) ||
       (*forFileStr == '\0') ||
       ((fP = (strcmp(forFileStr, "-")?
              fopen(forFileStr, "r"): stdin)) == NULL) ||
       ((forObj = WlzAssignObject(WlzReadObj(fP, &errNum), NULL)) == NULL))
    {
      ok = 0;
      (void )fprintf(stderr,
                     "%s: Failed to read foreground object from file %s.\n",
                     argv[0], forFileStr);
    }
    if(fP && strcmp(forFileStr, "-"))
    {
      (void )fclose(fP); fP = NULL;
    }
  }
  /* Check object types and parse the promote the default distance function
   * if required. */
  if(ok)
  {
    if(refObj->type != forObj->type)
    {
      ok = 0;
      (void )fprintf(stderr,
                     "%s: Foreground and reference object types differ.\n",
		     argv[0]);
    }
  }
  if((errNum == WLZ_ERR_NONE) && bnd)
  {
    tObj0 = tObj1 = NULL;
    tObj0 = WlzObjToBoundary(refObj, 1, &errNum);
    if(errNum == WLZ_ERR_NONE)
    {
      tObj1 = WlzBoundaryToObj(tObj0, WLZ_VERTEX_FILL, &errNum);
    }
    if(errNum == WLZ_ERR_NONE)
    {
      (void )WlzFreeObj(refObj);
      refObj = tObj1;
      tObj1 = NULL;
    }
    (void )WlzFreeObj(tObj0);
    (void )WlzFreeObj(tObj1);
  }
  /* Compute the distance transform object. */
  if(ok)
  {
    dstObj = WlzAssignObject(
    	     WlzDistanceTransform(forObj, refObj, dFn, dParam, &errNum), NULL);
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsgStr);
      (void )fprintf(stderr,
      		     "%s: Failed to compute distance object, %s.\n",
		     argv[0], errMsgStr);
    }
  }
  /* Output the distance transform object. */
  if(ok)
  {
    if((fP = (strcmp(outFileStr, "-")?
             fopen(outFileStr, "w"): stdout)) == NULL)
    {
      ok = 0;
      (void )fprintf(stderr,
                     "%s: Failed to open output file %s.\n",
                     argv[0], outFileStr);
    }
  }
  if(ok)
  {
    errNum = WlzWriteObj(fP, dstObj);
    if(errNum != WLZ_ERR_NONE)
    {
      ok = 0;
      (void )WlzStringFromErrorNum(errNum, &errMsgStr);
      (void )fprintf(stderr,
                     "%s: Failed to write output object, %s.\n",
                     argv[0], errMsgStr);
    }
  }
  (void )WlzFreeObj(forObj);
  (void )WlzFreeObj(refObj);
  (void )WlzFreeObj(dstObj);
  if(usage)
  {
    (void )fprintf(stderr,
    "Usage: %s [-b] [-d#] [-f#] [-p#] [-o#] [-h] [<Reference input file>]\n"
    "Computes a distance transform object which has the domain of the\n"
    "foreground object and values which are the distance from the reference\n"
    "object.\n"
    "Options are:\n"
    "  -b  Use the boundary of the reference object.\n"
    "  -d  Distance function:\n"
    "              0: Euclidean (2D and 3D, unimplemented)\n"
    "              1: octagonal (2D and 3D) - default\n"
    "              2: approximate Euclidean (2D and 3D)\n"
    "              4: 4-connected (2D)\n"
    "              8: 8-connected (2D)\n"
    "              6: 6-connected (3D)\n"
    "             18: 18-connected (3D)\n"
    "             26: 26-connected (3D)\n"
    "  -f  The foreground object file.\n" 
    "  -p  Distance function parameter, which is curently only used for\n"
    "      approximate Euclidean distance transforms. The value should\n"
    "      be >= 1, with larger values giving greater accuracy at the\n"
    "      cost of increased time. Default value - 10.0.\n"
    "  -o  Output object file.\n"
    "  -h  Help - prints this usage message\n",
    argv[0]);
  }
  return(!ok);
}
Beispiel #7
0
/*!
* \return	Centrality feature value in range [0.0-1.0].
* \ingroup	WlzFeatures
* \brief	Computes the centrality of a feature domain with respect
* 		to a boundary domain, where the domains are 2D. See
* 		WlzCentrality().
* \param	fObj			Feature domain object.
* \param	bObj			Boundary domain object.
* \param	nRay			Number of equally spaced rays projected
* 					from the centre of mass.
* \param	binFlg			Treat as binary object if non-zero.
* \param	dstMaxR			Destination pointer for maximum
* 					boundary radius, may be NULL.
* \param	dstErr			Destination error pointer, may be NULL.
*/
static double	WlzCentrality2D(WlzObject *fObj, WlzObject *bObj,
				int nRay, int binFlg,
				double *dstMaxR, WlzErrorNum *dstErr)
{
  int		idx;
  double	cent = 0.0,
  		fNum = 0.0,
		fDnm = 0.0,
		maxR = 0.0;
  WlzIVertex2	pos;
  WlzDVertex2	cmV;
  double	*pTbl = NULL;
  WlzObject	*tmpObj,
		*bndObj = NULL;
  WlzGreyP	gPix;
  WlzGreyWSpace gWsp;
  WlzIntervalWSpace iWsp;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  /* Get centre of mass of the boundary object. */
  cmV = WlzCentreOfMass2D(bObj, 1, NULL, &errNum);
  /* Get boundary of the boundary domain. */
  if(errNum == WLZ_ERR_NONE)
  {
    bndObj = WlzObjToBoundary(bObj, 0, &errNum);
  }
  /* Make sure the boundary is 8-connected. */
  if(errNum == WLZ_ERR_NONE)
  {
    tmpObj = WlzBoundTo8Bound(bndObj, &errNum);
    (void )WlzFreeObj(bndObj);
    bndObj = tmpObj;
  }
  /* Compute polar maximum boundary table. */
  if(errNum == WLZ_ERR_NONE)
  {
    if((pTbl = (double *)AlcMalloc(nRay * sizeof(double))) == NULL)
    {
      errNum = WLZ_ERR_MEM_ALLOC;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    WlzCentralityCompPolarTbl2D(cmV, nRay, pTbl, bndObj);
    if(dstMaxR != NULL)
    {
      for(idx = 0; idx < nRay; ++idx)
      {
        if(pTbl[idx] > maxR)
	{
	  maxR = pTbl[idx];
	}
      }
    }
  }
  (void )WlzFreeObj(bndObj);
  /* Scan through feature domain adding to feature values. */
  if(errNum == WLZ_ERR_NONE)
  {
    if(binFlg != 0)
    {
      errNum = WlzInitRasterScan(fObj, &iWsp, WLZ_RASTERDIR_ILIC);
      while((errNum = WlzNextInterval(&iWsp)) == WLZ_ERR_NONE)
      {
	pos.vtY = iWsp.linpos;
	for(pos.vtX = iWsp.lftpos; pos.vtX <= iWsp.rgtpos; ++pos.vtX)
	{
	  WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl, 1.0, pos);
	}
      }
    }
    else
    {
      errNum = WlzInitGreyScan(fObj, &iWsp, &gWsp);
      while((errNum = WlzNextGreyInterval(&iWsp)) == WLZ_ERR_NONE)
      {
	gPix = gWsp.u_grintptr;
	pos.vtY = iWsp.linpos;
	for(pos.vtX = iWsp.lftpos; pos.vtX <= iWsp.rgtpos; ++pos.vtX)
	{
	  switch(gWsp.pixeltype)
	  {
	    case WLZ_GREY_INT:
	      WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl,
	                            *(gPix.inp)++, pos);
	      break;
	    case WLZ_GREY_SHORT:
	      WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl,
	                            *(gPix.shp)++, pos);
	      break;
	    case WLZ_GREY_UBYTE:
	      WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl,
	                            *(gPix.ubp)++, pos);
	      break;
	    case WLZ_GREY_FLOAT:
	      WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl,
	                            *(gPix.flp)++, pos);
	      break;
	    case WLZ_GREY_DOUBLE:
	      WlzCentralityUpdate2D(&fNum, &fDnm, cmV, nRay, pTbl,
	                            *(gPix.dbp)++, pos);
	      break;
	    default:
	      errNum = WLZ_ERR_GREY_TYPE;
	      break;
	  }
	}
      }
    }
    if(errNum == WLZ_ERR_EOO)
    {
      errNum = WLZ_ERR_NONE;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    cent = (fabs(fDnm) > DBL_EPSILON)? fNum / fDnm: DBL_MAX;
    if(dstMaxR != NULL)
    {
      *dstMaxR = maxR;
    }
  }
  AlcFree(pTbl);
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(cent);
}