https://github.com/ma-tech/Woolz
Raw File
Tip revision: a669baf40caca7cbe295d355c367023360fbea5e authored by Bill Hill on 02 February 2016, 10:40:55 UTC
Now version 1.6.8.
Tip revision: a669baf
WlzBoundingBox.c
#if defined(__GNUC__)
#ident "University of Edinburgh $Id$"
#else
static char _WlzBoundingBox_c[] = "University of Edinburgh $Id$";
#endif
/*!
* \file         libWlz/WlzBoundingBox.c
* \author       Bill Hill
* \date         March 1999
* \version      $Id$
* \par
* Address:
*               MRC Human Genetics Unit,
*               MRC Institute of Genetics and Molecular Medicine,
*               University of Edinburgh,
*               Western General Hospital,
*               Edinburgh, EH4 2XU, UK.
* \par
* Copyright (C), [2012],
* The University Court of the University of Edinburgh,
* Old College, Edinburgh, UK.
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be
* useful but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE.  See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA  02110-1301, USA.
* \brief	Functions for computing the axis aligned bounding box
* 		of objects.
* \ingroup	WlzFeatures
*/

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <Wlz.h>

static WlzDBox3			WlzBoundingBoxBound3D(
				  WlzBoundList *,
				  WlzErrorNum *);
static WlzDBox3			WlzBoundingBoxPoly3D(
				  WlzPolygonDomain *,
				  WlzErrorNum *);
static WlzDBox3			WlzBoundingBoxTransObj3D(
				  WlzObject *,
				  WlzAffineTransform *,
				  WlzErrorNum *);
static WlzDBox3 		WlzBoundingBoxContour3D(
				  WlzContour *ctr,
				  WlzErrorNum *dstErr);
static WlzDBox3 		WlzBoundingBoxCompound3D(
				  WlzCompoundArray *cObj,
				  WlzErrorNum *dstErr);

/*!
* \return	2D integer bounding box.
* \ingroup      WlzFeatures
* \brief	Computes the 2D integer axis aligned bounding box of the
*		given object.
* \param	inObj			The given object.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzIBox2	WlzBoundingBox2I(WlzObject *inObj, WlzErrorNum *dstErr)
{
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  WlzIBox2	bBox2I;
  WlzIBox3	bBox3I;

  bBox3I = WlzBoundingBox3I(inObj, &errNum);
  bBox2I.xMin = bBox3I.xMin;
  bBox2I.yMin = bBox3I.yMin;
  bBox2I.xMax = bBox3I.xMax;
  bBox2I.yMax = bBox3I.yMax;
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox2I);
}

/*!
* \return	2D double precision bounding box.
* \ingroup      WlzFeatures
* \brief	Computes the 2D double precision axis aligned bounding box
*		of the given object.
* \param	inObj			The given object.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzDBox2	WlzBoundingBox2D(WlzObject *inObj, WlzErrorNum *dstErr)
{
  WlzErrorNum	errNum = WLZ_ERR_NONE;
  WlzDBox2	bBox2D;
  WlzDBox3	bBox3D;

  bBox3D = WlzBoundingBox3D(inObj, &errNum);
  bBox2D.xMin = bBox3D.xMin;
  bBox2D.yMin = bBox3D.yMin;
  bBox2D.xMax = bBox3D.xMax;
  bBox2D.yMax = bBox3D.yMax;
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox2D);
}

/*!
* \return	3D integer bounding box.
* \ingroup      WlzFeatures
* \brief	Computes the integer 3D axis aligned bounding box of the
*		given object.
* \param	inObj			The given object.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzIBox3	WlzBoundingBox3I(WlzObject *inObj, WlzErrorNum *dstErr)
{
  WlzIBox3	bBox3I;
  WlzDBox3	bBox3D;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  bBox3I.xMin = 0;
  bBox3I.xMax = 0;
  bBox3I.yMin = 0;
  bBox3I.yMax = 0;
  bBox3I.zMin = 0;
  bBox3I.zMax = 0;
  if(inObj == NULL)
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else
  {
    switch(inObj->type)
    {
      case WLZ_2D_DOMAINOBJ:
	if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else
	{
	  switch(inObj->domain.core->type)
	  {
	    case WLZ_INTERVALDOMAIN_INTVL: /* FALLTHROUGH */
            case WLZ_INTERVALDOMAIN_RECT:
	      bBox3I.xMin = inObj->domain.i->kol1;
	      bBox3I.yMin = inObj->domain.i->line1;
	      bBox3I.xMax = inObj->domain.i->lastkl;
	      bBox3I.yMax = inObj->domain.i->lastln;
	      break;
	    default:
	      errNum = WLZ_ERR_DOMAIN_TYPE;
	      break;
	  }
	}
        break;
      case WLZ_3D_DOMAINOBJ:
        if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else
	{
	  if(inObj->domain.core->type != WLZ_PLANEDOMAIN_DOMAIN)
	  {
	    errNum = WLZ_ERR_DOMAIN_TYPE;
	  }
	  else
	  {
	    bBox3I.xMin = inObj->domain.p->kol1;
	    bBox3I.yMin = inObj->domain.p->line1;
	    bBox3I.zMin = inObj->domain.p->plane1;
	    bBox3I.xMax = inObj->domain.p->lastkl;
	    bBox3I.yMax = inObj->domain.p->lastln;
	    bBox3I.zMax = inObj->domain.p->lastpl;
	  }
	}
	break;
      case WLZ_TRANS_OBJ:
        if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else if(inObj->values.core == NULL)
	{
	  errNum = WLZ_ERR_VALUES_NULL;
	}
	else if(inObj->domain.core->type != (WlzObjectType)
	                                    WLZ_TRANSFORM_2D_AFFINE)
	{
	  errNum = WLZ_ERR_DOMAIN_TYPE;
	}
	else
	{
	  bBox3D = WlzBoundingBoxTransObj3D(inObj->values.obj,
	  				    inObj->domain.t, &errNum);
	  bBox3I = WlzBoundingBox3DTo3I(bBox3D);
	}
	break;
      case WLZ_2D_POLYGON:
        if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else
	{
          bBox3D = WlzBoundingBoxPoly3D(inObj->domain.poly, &errNum);
	  bBox3I = WlzBoundingBox3DTo3I(bBox3D);
	}
        break;
      case WLZ_BOUNDLIST:
        if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else
	{
          bBox3D = WlzBoundingBoxBound3D(inObj->domain.b, &errNum);
	  bBox3I = WlzBoundingBox3DTo3I(bBox3D);
	}
	break;
      case WLZ_CONTOUR:
	if(inObj->domain.ctr == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else
	{
	  bBox3D = WlzBoundingBoxContour3D(inObj->domain.ctr, &errNum);
	  bBox3I = WlzBoundingBox3DTo3I(bBox3D);
	}
        break;
      case WLZ_COMPOUND_ARR_1: /* FALLTHROUGH */
      case WLZ_COMPOUND_ARR_2:
        bBox3D = WlzBoundingBoxCompound3D((WlzCompoundArray *)inObj, &errNum);
	bBox3I = WlzBoundingBox3DTo3I(bBox3D);
        break;
      case WLZ_EMPTY_OBJ:
      case WLZ_AFFINE_TRANS:
      case WLZ_HISTOGRAM:
      case WLZ_PROPERTY_OBJ:
      case WLZ_CONV_HULL:
      case WLZ_3D_WARP_TRANS:
      case WLZ_3D_POLYGON:
      case WLZ_RECTANGLE:
      case WLZ_CONVOLVE_INT:
      case WLZ_CONVOLVE_FLOAT:
      case WLZ_WARP_TRANS:
      case WLZ_FMATCHOBJ:
      case WLZ_TEXT:
      case WLZ_COMPOUND_LIST_1:
      case WLZ_COMPOUND_LIST_2:
      default:
	errNum = WLZ_ERR_OBJECT_TYPE;
	break;
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox3I);
}

/*!
* \return	3D double precision bounding box.
* \ingroup      WlzFeatures
* \brief	Computes the double precision 3D axis aligned bounding box
*		of the given object.
* \param	inObj			The given object.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzDBox3	WlzBoundingBox3D(WlzObject *inObj, WlzErrorNum *dstErr)
{
  WlzDBox3	bBox3D;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  bBox3D.xMin = 0.0;
  bBox3D.xMax = 0.0;
  bBox3D.yMin = 0.0;
  bBox3D.yMax = 0.0;
  bBox3D.zMin = 0.0;
  bBox3D.zMax = 0.0;
  if(inObj == NULL)
  {
    errNum = WLZ_ERR_OBJECT_NULL;
  }
  else
  {
    switch(inObj->type)
    {
      case WLZ_2D_DOMAINOBJ:
	if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else
	{
	  switch(inObj->domain.core->type)
	  {
	    case WLZ_INTERVALDOMAIN_INTVL: /* FALLTHROUGH */
            case WLZ_INTERVALDOMAIN_RECT:
	      bBox3D.xMin = inObj->domain.i->kol1;
	      bBox3D.yMin = inObj->domain.i->line1;
	      bBox3D.xMax = inObj->domain.i->lastkl;
	      bBox3D.yMax = inObj->domain.i->lastln;
	      break;
	    default:
	      errNum = WLZ_ERR_DOMAIN_TYPE;
	      break;
	  }
	}
        break;
      case WLZ_3D_DOMAINOBJ:
        if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else
	{
	  if(inObj->domain.core->type != WLZ_PLANEDOMAIN_DOMAIN)
	  {
	    errNum = WLZ_ERR_DOMAIN_TYPE;
	  }
	  else
	  {
	    bBox3D.xMin = inObj->domain.p->kol1;
	    bBox3D.yMin = inObj->domain.p->line1;
	    bBox3D.zMin = inObj->domain.p->plane1;
	    bBox3D.xMax = inObj->domain.p->lastkl;
	    bBox3D.yMax = inObj->domain.p->lastln;
	    bBox3D.zMax = inObj->domain.p->lastpl;
	  }
	}
	break;
      case WLZ_TRANS_OBJ:
        if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else if(inObj->values.core == NULL)
	{
	  errNum = WLZ_ERR_VALUES_NULL;
	}
	else if(inObj->domain.core->type != (WlzObjectType )
	                                    WLZ_TRANSFORM_2D_AFFINE)
	{
	  errNum = WLZ_ERR_DOMAIN_TYPE;
	}
	else
	{
	  bBox3D = WlzBoundingBoxTransObj3D(inObj->values.obj,
	  				    inObj->domain.t, &errNum);
	}
	break;
      case WLZ_2D_POLYGON:
        if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else
	{
          bBox3D = WlzBoundingBoxPoly3D(inObj->domain.poly, &errNum);
	}
        break;
      case WLZ_BOUNDLIST:
        if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else
	{
          bBox3D = WlzBoundingBoxBound3D(inObj->domain.b, &errNum);
	}
	break;
      case WLZ_CONTOUR:
	if(inObj->domain.ctr == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else
	{
	  bBox3D = WlzBoundingBoxContour3D(inObj->domain.ctr, &errNum);
	}
        break;
      case WLZ_COMPOUND_ARR_1: /* FALLTHROUGH */
      case WLZ_COMPOUND_ARR_2:
        bBox3D = WlzBoundingBoxCompound3D((WlzCompoundArray *)inObj, &errNum);
	break;
      case WLZ_CMESH_2D:
	if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else if(inObj->domain.core->type != WLZ_CMESH_2D)
	{
	  errNum = WLZ_ERR_DOMAIN_TYPE;
	}
	else
	{
	  WlzCMeshUpdateBBox2D(inObj->domain.cm2);
          bBox3D.xMin = inObj->domain.cm2->bBox.xMin;
          bBox3D.yMin = inObj->domain.cm2->bBox.yMin;
          bBox3D.zMin = 0.0;
          bBox3D.xMax = inObj->domain.cm2->bBox.xMax;
          bBox3D.yMax = inObj->domain.cm2->bBox.yMax;
          bBox3D.zMax = 0.0;
	}
	break;
      case WLZ_CMESH_2D5:
	if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else if(inObj->domain.core->type != WLZ_CMESH_2D5)
	{
	  errNum = WLZ_ERR_DOMAIN_TYPE;
	}
	else
	{
	  WlzCMeshUpdateBBox2D5(inObj->domain.cm2d5);
          bBox3D.xMin = inObj->domain.cm2d5->bBox.xMin;
          bBox3D.yMin = inObj->domain.cm2d5->bBox.yMin;
          bBox3D.zMin = inObj->domain.cm2d5->bBox.zMin;
          bBox3D.xMax = inObj->domain.cm2d5->bBox.xMax;
          bBox3D.yMax = inObj->domain.cm2d5->bBox.yMax;
          bBox3D.zMax = inObj->domain.cm2d5->bBox.zMax;
	}
	break;
      case WLZ_CMESH_3D:
	if(inObj->domain.core == NULL)
	{
	  errNum = WLZ_ERR_DOMAIN_NULL;
	}
	else if(inObj->domain.core->type != WLZ_CMESH_3D)
	{
	  errNum = WLZ_ERR_DOMAIN_TYPE;
	}
	else
	{
	  WlzCMeshUpdateBBox3D(inObj->domain.cm3);
          bBox3D.xMin = inObj->domain.cm3->bBox.xMin;
          bBox3D.yMin = inObj->domain.cm3->bBox.yMin;
          bBox3D.zMin = inObj->domain.cm3->bBox.zMin;
          bBox3D.xMax = inObj->domain.cm3->bBox.xMax;
          bBox3D.yMax = inObj->domain.cm3->bBox.yMax;
          bBox3D.zMax = inObj->domain.cm3->bBox.zMax;
	}
        break;
      case WLZ_EMPTY_OBJ:
      case WLZ_AFFINE_TRANS:
      case WLZ_HISTOGRAM:
      case WLZ_PROPERTY_OBJ:
      case WLZ_CONV_HULL:
      case WLZ_3D_WARP_TRANS:
      case WLZ_3D_POLYGON:
      case WLZ_RECTANGLE:
      case WLZ_CONVOLVE_INT:
      case WLZ_CONVOLVE_FLOAT:
      case WLZ_WARP_TRANS:
      case WLZ_FMATCHOBJ:
      case WLZ_TEXT:
      case WLZ_COMPOUND_LIST_1:
      case WLZ_COMPOUND_LIST_2:
      default:
	errNum = WLZ_ERR_OBJECT_TYPE;
	break;
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox3D);
}

/*!
* \return	Double precision 3D bounding box.
* \brief	Computes the bounding box of the given 3D double precision
*		vertices.
* \param	nVtx			Number of vertices.
* \param	vtx			Vertices.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzDBox3	WlzBoundingBoxVtx3D(int nVtx, WlzDVertex3 *vtx,
				    WlzErrorNum *dstErr)
{
  int		cnt;
  WlzDBox3	bBox3D;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  if((nVtx <= 0) || (vtx == NULL))
  {
    errNum = WLZ_ERR_PARAM_NULL;
  }
  else
  {
    cnt = nVtx;
    bBox3D.xMin = bBox3D.xMax = vtx->vtX;
    bBox3D.yMin = bBox3D.yMax = vtx->vtY;
    bBox3D.zMin = bBox3D.zMax = vtx->vtZ;
    while(--cnt > 0)
    {
      ++vtx;
      if(vtx->vtX < bBox3D.xMin)
      {
	bBox3D.xMin = vtx->vtX;
      }
      else if(vtx->vtX > bBox3D.xMax)
      {
        bBox3D.xMax = vtx->vtX;
      }
      if(vtx->vtY < bBox3D.yMin)
      {
	bBox3D.yMin = vtx->vtY;
      }
      else if(vtx->vtY > bBox3D.yMax)
      {
        bBox3D.yMax = vtx->vtY;
      }
      if(vtx->vtZ < bBox3D.zMin)
      {
	bBox3D.zMin = vtx->vtZ;
      }
      else if(vtx->vtZ > bBox3D.zMax)
      {
        bBox3D.zMax = vtx->vtZ;
      }
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox3D);
}

/*!
* \return	Integer 3D bounding box.
* \brief	Computes the bounding box of the given 3D integer vertices.
* \param	nVtx			Number of vertices.
* \param	vtx			Vertices.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzIBox3	WlzBoundingBoxVtx3I(int nVtx, WlzIVertex3 *vtx,
				    WlzErrorNum *dstErr)
{
  int		cnt;
  WlzIBox3	bBox3I;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  if((nVtx <= 0) || (vtx == NULL))
  {
    errNum = WLZ_ERR_PARAM_NULL;
  }
  else
  {
    cnt = nVtx;
    bBox3I.xMin = bBox3I.xMax = vtx->vtX;
    bBox3I.yMin = bBox3I.yMax = vtx->vtY;
    bBox3I.zMin = bBox3I.zMax = vtx->vtZ;
    while(--cnt > 0)
    {
      ++vtx;
      if(vtx->vtX < bBox3I.xMin)
      {
	bBox3I.xMin = vtx->vtX;
      }
      else if(vtx->vtX > bBox3I.xMax)
      {
        bBox3I.xMax = vtx->vtX;
      }
      if(vtx->vtY < bBox3I.yMin)
      {
	bBox3I.yMin = vtx->vtY;
      }
      else if(vtx->vtY > bBox3I.yMax)
      {
        bBox3I.yMax = vtx->vtY;
      }
      if(vtx->vtZ < bBox3I.zMin)
      {
	bBox3I.zMin = vtx->vtZ;
      }
      else if(vtx->vtZ > bBox3I.zMax)
      {
        bBox3I.zMax = vtx->vtZ;
      }
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox3I);
}

/*!
* \return	3D bounding box.
* \ingroup      WlzFeatures
* \brief	Computes the 3D axis aligned bounding box of the
*		transformed object.
* \param	inObj			Input object.
* \param	trans			Given transform.
* \param	dstErr			Destination error pointer, may be NULL.
*/
static WlzDBox3	WlzBoundingBoxTransObj3D(WlzObject *inObj,
					 WlzAffineTransform *trans,
				         WlzErrorNum *dstErr)
{
  WlzDBox3	tBox3D,
  		bBox3D;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  bBox3D.xMin = 0.0;
  bBox3D.xMax = 0.0;
  bBox3D.yMin = 0.0;
  bBox3D.yMax = 0.0;
  bBox3D.zMin = 0.0;
  bBox3D.zMax = 0.0;
  tBox3D = WlzBoundingBox3D(inObj, &errNum);
  if(errNum == WLZ_ERR_NONE)
  {
    bBox3D = WlzAffineTransformBBoxD3(trans, tBox3D, &errNum);
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox3D);
}

/*!
* \return	3D bounding box.
* \ingroup	WlzFeatures
* \brief	Computes the 3D axis aligned bounding box of the
* 		compound array object.
* \param	WlzCompoundArray *cObjdstErr
*/
static WlzDBox3 WlzBoundingBoxCompound3D(WlzCompoundArray *cObj,
					 WlzErrorNum *dstErr)
{
  WlzDBox3	tBox3D,
  		bBox3D;
  WlzErrorNum   errNum = WLZ_ERR_NONE;

  if(cObj->n < 1)
  {
    errNum = WLZ_ERR_OBJECT_DATA;
  }
  else
  {
    int		idx = 0;

    while((idx < cObj->n) &&
          ((cObj->o[idx] == NULL) || (cObj->o[idx]->type == WLZ_EMPTY_OBJ)))
    {
      ++idx;
    }
    if(idx >= cObj->n)
    {
      errNum = WLZ_ERR_OBJECT_TYPE;
    }
    else
    {
      bBox3D = WlzBoundingBox3D(cObj->o[idx], &errNum);
      while((errNum == WLZ_ERR_NONE) && (++idx < cObj->n))
      {
	if((cObj->o[idx] != NULL) && (cObj->o[idx]->type != WLZ_EMPTY_OBJ))
	{
	  tBox3D = WlzBoundingBox3D(cObj->o[idx], &errNum);
	  if(errNum == WLZ_ERR_NONE)
	  {
	    bBox3D = WlzBoundingBoxUnion3D(bBox3D, tBox3D);
	  }
	}
      }
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox3D);
}

/*!
* \return	3D bounding box.
* \ingroup      WlzFeatures
* \brief	Computes the 3D axis aligned bounding box of the polygon
* 		domain.
* \param	poly			The given polygon domain.
* \param	dstErr			Destination error pointer, may be NULL.
*/
static WlzDBox3	WlzBoundingBoxPoly3D(WlzPolygonDomain *poly,
				     WlzErrorNum *dstErr)
{
  int		tI0,
  		idx;
  WlzIVertex2	*tIVxP;
  WlzFVertex2	*tFVxP;
  WlzDVertex2	*tDVxP;
  WlzDBox3	bBox3D;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  bBox3D.xMin = 0.0;
  bBox3D.xMax = 0.0;
  bBox3D.yMin = 0.0;
  bBox3D.yMax = 0.0;
  bBox3D.zMin = 0.0;
  bBox3D.zMax = 0.0;
  switch(poly->type)
  {
    case WLZ_POLYGON_INT:
      if((idx = poly->nvertices) > 0)
      {
	tIVxP = poly->vtx;
	bBox3D.xMax = bBox3D.xMin = tIVxP->vtX;
	bBox3D.yMax = bBox3D.yMin = tIVxP->vtY;
	while(--idx > 0)
	{
	  if((tI0 = tIVxP->vtX) < bBox3D.xMin)
	  {
	    bBox3D.xMin = tI0;
	  }
	  else if(tI0 > bBox3D.xMax)
	  {
	    bBox3D.xMax = tI0;
	  }
	  if((tI0 = tIVxP->vtY) < bBox3D.yMin)
	  {
	    bBox3D.yMin = tI0;
	  }
	  else if(tI0 > bBox3D.yMax)
	  {
	    bBox3D.yMax = tI0;
	  }
	  ++tIVxP;
	}
      }
      break;
    case WLZ_POLYGON_FLOAT:
      if((idx = poly->nvertices) > 0)
      {
	tFVxP = (WlzFVertex2 *)(poly->vtx);
	bBox3D.xMax = bBox3D.xMin = WLZ_NINT(tFVxP->vtX);
	bBox3D.yMax = bBox3D.yMin = WLZ_NINT(tFVxP->vtY);
	while(--idx > 0)
	{
	  if((tI0 = WLZ_NINT(tFVxP->vtX)) < bBox3D.xMin)
	  {
	    bBox3D.xMin = tI0;
	  }
	  else if(tI0 > bBox3D.xMax)
	  {
	    bBox3D.xMax = tI0;
	  }
	  if((tI0 = WLZ_NINT(tFVxP->vtY)) < bBox3D.yMin)
	  {
	    bBox3D.yMin = tI0;
	  }
	  else if(tI0 > bBox3D.yMax)
	  {
	    bBox3D.yMax = tI0;
	  }
	  ++tFVxP;
	}
      }
      break;
    case WLZ_POLYGON_DOUBLE:
      if((idx = poly->nvertices) > 0)
      {
	tDVxP = (WlzDVertex2 *)(poly->vtx);
	bBox3D.xMax = bBox3D.xMin = WLZ_NINT(tDVxP->vtX);
	bBox3D.yMax = bBox3D.yMin = WLZ_NINT(tDVxP->vtY);
	while(--idx > 0)
	{
	  if((tI0 = WLZ_NINT(tDVxP->vtX)) < bBox3D.xMin)
	  {
	    bBox3D.xMin = tI0;
	  }
	  else if(tI0 > bBox3D.xMax)
	  {
	    bBox3D.xMax = tI0;
	  }
	  if((tI0 = WLZ_NINT(tDVxP->vtY)) < bBox3D.yMin)
	  {
	    bBox3D.yMin = tI0;
	  }
	  else if(tI0 > bBox3D.yMax)
	  {
	    bBox3D.yMax = tI0;
	  }
	  ++tDVxP;
	}
      }
      break;
    default:
      errNum = WLZ_ERR_DOMAIN_TYPE;
      break;
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox3D);
}

/*!
* \return	3D bounding box.
* \ingroup      WlzFeatures
* \brief	Computes the 3D axis aligned bounding box of the
*		boundary list.
* \param	bound			The given boundary list.
* \param	dstErr			Destination error pointer, may be NULL.
*/
static WlzDBox3	WlzBoundingBoxBound3D(WlzBoundList *bound,
				      WlzErrorNum *dstErr)
{
  WlzDBox3	bBox3D,
  		tBox3D;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  bBox3D = WlzBoundingBoxPoly3D(bound->poly, &errNum);
  if(bound->next && (errNum == WLZ_ERR_NONE))
  {
    tBox3D = WlzBoundingBoxBound3D(bound->next, &errNum);
    if(tBox3D.xMin < bBox3D.xMin)
    {
      bBox3D.xMin = tBox3D.xMin;
    }
    if(tBox3D.yMin < bBox3D.yMin)
    {
      bBox3D.yMin = tBox3D.yMin;
    }
    if(tBox3D.zMin < bBox3D.zMin)
    {
      bBox3D.zMin = tBox3D.zMin;
    }
    if(tBox3D.xMax > bBox3D.xMax)
    {
      bBox3D.xMax = tBox3D.xMax;
    }
    if(tBox3D.yMax > bBox3D.yMax)
    {
      bBox3D.yMax = tBox3D.yMax;
    }
    if(tBox3D.zMax > bBox3D.zMax)
    {
      bBox3D.zMax = tBox3D.zMax;
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox3D);
}

/*!
* \return	3D bounding box.
* \ingroup      WlzFeatures
* \brief	Computes the 3D axis aligned bounding box of the contour.
* \param	ctr			The given boundary list.
* \param	dstErr			Destination error pointer, may be NULL.
*/
static WlzDBox3 WlzBoundingBoxContour3D(WlzContour *ctr, WlzErrorNum *dstErr)
{
  WlzDBox3	bBox3D;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  bBox3D = WlzBoundingBoxGModel3D(ctr->model, &errNum);
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox3D);
}

/*!
* \return	3D bounding box.
* \ingroup	WlzFeatures
* \brief	Computes the 3D axis aligned bounding box of the 3D geometric
* 		model. It is an error if the model is not a 3D model.
* \param	model			Given model.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzDBox3 	WlzBoundingBoxGModel3D(WlzGMModel *model, WlzErrorNum *dstErr)
{
  WlzGMShell	*shell0,
  		*shell1;
  WlzDBox3	sBox3D,
  		bBox3D;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  if(model == NULL)
  {
    errNum =  WLZ_ERR_DOMAIN_NULL;
  }
  else
  {
    switch(model->type)
    {
      case WLZ_GMMOD_3I: /* FALLTHROUGH */
      case WLZ_GMMOD_3D: /* FALLTHROUGH */
      case WLZ_GMMOD_3N:
	break;
      default:
        errNum = WLZ_ERR_DOMAIN_TYPE;
	break;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    if((shell0 = model->child) == NULL)
    {
      errNum = WLZ_ERR_DOMAIN_DATA;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    /* Find the bounding box of all the GM's shell's bounding boxes. */
    shell1 = shell0->next;
    errNum = WlzGMShellGetGBB3D(shell0, &bBox3D);
    while((errNum == WLZ_ERR_NONE) && (shell1->idx != shell0->idx))
    {
      if((errNum = WlzGMShellGetGBB3D(shell1, &sBox3D)) == WLZ_ERR_NONE)
      {
	if(sBox3D.xMin < bBox3D.xMin)
	{
	  bBox3D.xMin = sBox3D.xMin;
	}
	if(sBox3D.yMin < bBox3D.yMin)
	{
	  bBox3D.yMin = sBox3D.yMin;
	}
	if(sBox3D.zMin < bBox3D.zMin)
	{
	  bBox3D.zMin = sBox3D.zMin;
	}
	if(sBox3D.xMax > bBox3D.xMax)
	{
	  bBox3D.xMax = sBox3D.xMax;
	}
	if(sBox3D.yMax > bBox3D.yMax)
	{
	  bBox3D.yMax = sBox3D.yMax;
	}
	if(sBox3D.zMax > bBox3D.zMax)
	{
	  bBox3D.zMax = sBox3D.zMax;
	}
        shell1 = shell1->next;
      }
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox3D);
}

/*!
* \return	2D bounding box.
* \ingroup	WlzFeatures
* \brief	Computes the 2D axis aligned bounding box of the 2D geometric
* 		model. It is an error if the model is not a 2D model.
* \param	model			Given model.
* \param	dstErr			Destination error pointer, may be NULL.
*/
WlzDBox2 	WlzBoundingBoxGModel2D(WlzGMModel *model, WlzErrorNum *dstErr)
{
  WlzGMShell	*shell0,
  		*shell1;
  WlzDBox2	sBox2D,
  		bBox2D;
  WlzErrorNum	errNum = WLZ_ERR_NONE;

  if(model == NULL)
  {
    errNum =  WLZ_ERR_DOMAIN_NULL;
  }
  else
  {
    switch(model->type)
    {
      case WLZ_GMMOD_2I: /* FALLTHROUGH */
      case WLZ_GMMOD_2D: /* FALLTHROUGH */
      case WLZ_GMMOD_2N:
	break;
      default:
        errNum = WLZ_ERR_DOMAIN_TYPE;
	break;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    if((shell0 = model->child) == NULL)
    {
      errNum = WLZ_ERR_DOMAIN_DATA;
    }
  }
  if(errNum == WLZ_ERR_NONE)
  {
    /* Find the bounding box of all the GM's shell's bounding boxes. */
    shell1 = shell0->next;
    errNum = WlzGMShellGetGBB2D(shell0, &bBox2D);
    while((errNum == WLZ_ERR_NONE) && (shell1->idx != shell0->idx))
    {
      if((errNum = WlzGMShellGetGBB2D(shell1, &sBox2D)) == WLZ_ERR_NONE)
      {
	if(sBox2D.xMin < bBox2D.xMin)
	{
	  bBox2D.xMin = sBox2D.xMin;
	}
	if(sBox2D.yMin < bBox2D.yMin)
	{
	  bBox2D.yMin = sBox2D.yMin;
	}
	if(sBox2D.xMax > bBox2D.xMax)
	{
	  bBox2D.xMax = sBox2D.xMax;
	}
	if(sBox2D.yMax > bBox2D.yMax)
	{
	  bBox2D.yMax = sBox2D.yMax;
	}
        shell1 = shell1->next;
      }
    }
  }
  if(dstErr)
  {
    *dstErr = errNum;
  }
  return(bBox2D);
}

/*!
* \return	Integer bounding box.
* \ingroup	WlzFeatures
* \brief	Converts a 2D double precision bounding box to an integer
*		bounding box. There is no checking done for underflows or
*		overflows.
* \param	bBox2D			Double precision bounding box.
*/
WlzIBox2	WlzBoundingBox2DTo2I(WlzDBox2 bBox2D)
{
  WlzIBox2	bBox2I;

  bBox2I.xMin = (int )floor(bBox2D.xMin);
  bBox2I.yMin = (int )floor(bBox2D.yMin);
  bBox2I.xMax = (int )ceil(bBox2D.xMax);
  bBox2I.yMax = (int )ceil(bBox2D.yMax);
  return(bBox2I);
}

/*!
* \return	Double precision bounding box.
* \ingroup	WlzFeatures
* \brief	Converts a 2D integer bounding box to an double precision
*		bounding box.
* \param	bBox2I			Double precision bounding box.
*/
WlzDBox2	WlzBoundingBox2ITo2D(WlzIBox2 bBox2I)
{
  WlzDBox2	bBox2D;

  bBox2D.xMin = bBox2I.xMin;
  bBox2D.yMin = bBox2I.yMin;
  bBox2D.xMax = bBox2I.xMax;
  bBox2D.yMax = bBox2I.yMax;
  return(bBox2D);
}

/*!
* \return	Integer bounding box.
* \ingroup	WlzFeatures
* \brief	Converts a 3D double precision bounding box to an integer
*		bounding box. There is no checking done for underflows or
*		overflows.
* \param	bBox3D			Double precision bounding box.
*/
WlzIBox3	WlzBoundingBox3DTo3I(WlzDBox3 bBox3D)
{
  WlzIBox3	bBox3I;

  bBox3I.xMin = (int )floor(bBox3D.xMin);
  bBox3I.yMin = (int )floor(bBox3D.yMin);
  bBox3I.zMin = (int )floor(bBox3D.zMin);
  bBox3I.xMax = (int )ceil(bBox3D.xMax);
  bBox3I.yMax = (int )ceil(bBox3D.yMax);
  bBox3I.zMax = (int )ceil(bBox3D.zMax);
  return(bBox3I);
}

/*!
* \return	Double precision bounding box.
* \ingroup	WlzFeatures
* \brief	Converts a 3D integer bounding box to an double precision
*		bounding box.
* \param	bBox3I			Integer bounding box.
*/
WlzDBox3	WlzBoundingBox3ITo3D(WlzIBox3 bBox3I)
{
  WlzDBox3	bBox3D;

  bBox3D.xMin = bBox3I.xMin;
  bBox3D.yMin = bBox3I.yMin;
  bBox3D.zMin = bBox3I.zMin;
  bBox3D.xMax = bBox3I.xMax;
  bBox3D.yMax = bBox3I.yMax;
  bBox3D.zMax = bBox3I.zMax;
  return(bBox3D);
}

/*!
* \return	Single precision bounding box.
* \ingroup	WlzFeatures
* \brief	Converts a 3D double bounding box to a single precision
*		bounding box.
* \param	bBox3D			Double precision bounding box.
*/
WlzFBox3	WlzBoundingBox3DTo3F(WlzDBox3 bBox3D)
{
  WlzFBox3	bBox3F;

  bBox3F.xMin = (float )(bBox3D.xMin);
  bBox3F.yMin = (float )(bBox3D.yMin);
  bBox3F.zMin = (float )(bBox3D.zMin);
  bBox3F.xMax = (float )(bBox3D.xMax);
  bBox3F.yMax = (float )(bBox3D.yMax);
  bBox3F.zMax = (float )(bBox3D.zMax);
  return(bBox3F);
}

/*!
* \return	Double precision bounding box.
* \ingroup	WlzFeatures
* \brief	Converts a 3D single bounding box to a double precision
*		bounding box.
* \param	bBox3F			Single precision bounding box.
*/
WlzDBox3	WlzBoundingBox3FTo3D(WlzFBox3 bBox3F)
{
  WlzDBox3	bBox3D;

  bBox3D.xMin = bBox3F.xMin;
  bBox3D.yMin = bBox3F.yMin;
  bBox3D.zMin = bBox3F.zMin;
  bBox3D.xMax = bBox3F.xMax;
  bBox3D.yMax = bBox3F.yMax;
  bBox3D.zMax = bBox3F.zMax;
  return(bBox3D);
}

/*!
* \return	Axis alligned 2D integer bounding box.
* \ingroup	WlzFeatures
* \brief	Computes the 2D integer bounding box which
*		encloses the given pair of bounding boxes.
* \param	box0			First bounding box.
* \param	box1			Second bounding box.
*/
WlzIBox2	WlzBoundingBoxUnion2I(WlzIBox2 box0, WlzIBox2 box1)
{
  if(box1.xMin < box0.xMin)
  {
    box0.xMin = box1.xMin;
  }
  if(box1.xMax > box0.xMax)
  {
    box0.xMax = box1.xMax;
  }
  if(box1.yMin < box0.yMin)
  {
    box0.yMin = box1.yMin;
  }
  if(box1.yMax > box0.yMax)
  {
    box0.yMax = box1.yMax;
  }
  return(box0);
}

/*!
* \return	Axis alligned 2D single precision bounding box.
* \ingroup	WlzFeatures
* \brief	Computes the 2D single precision bounding box which
*		encloses the given pair of bounding boxes.
* \param	box0			First bounding box.
* \param	box1			Second bounding box.
*/
WlzFBox2	WlzBoundingBoxUnion2F(WlzFBox2 box0, WlzFBox2 box1)
{
  if(box1.xMin < box0.xMin)
  {
    box0.xMin = box1.xMin;
  }
  if(box1.xMax > box0.xMax)
  {
    box0.xMax = box1.xMax;
  }
  if(box1.yMin < box0.yMin)
  {
    box0.yMin = box1.yMin;
  }
  if(box1.yMax > box0.yMax)
  {
    box0.yMax = box1.yMax;
  }
  return(box0);
}

/*!
* \return	Axis alligned 2D double precision bounding box.
* \ingroup	WlzFeatures
* \brief	Computes the 2D double precision bounding box which
*		encloses the given pair of bounding boxes.
* \param	box0			First bounding box.
* \param	box1			Second bounding box.
*/
WlzDBox2	WlzBoundingBoxUnion2D(WlzDBox2 box0, WlzDBox2 box1)
{
  if(box1.xMin < box0.xMin)
  {
    box0.xMin = box1.xMin;
  }
  if(box1.xMax > box0.xMax)
  {
    box0.xMax = box1.xMax;
  }
  if(box1.yMin < box0.yMin)
  {
    box0.yMin = box1.yMin;
  }
  if(box1.yMax > box0.yMax)
  {
    box0.yMax = box1.yMax;
  }
  return(box0);
}

/*!
* \return	Axis alligned 3D integer bounding box.
* \ingroup	WlzFeatures
* \brief	Computes the 3D integer bounding box which
*		encloses the given pair of bounding boxes.
* \param	box0			First bounding box.
* \param	box1			Second bounding box.
*/
WlzIBox3	WlzBoundingBoxUnion3I(WlzIBox3 box0, WlzIBox3 box1)
{
  if(box1.xMin < box0.xMin)
  {
    box0.xMin = box1.xMin;
  }
  if(box1.xMax > box0.xMax)
  {
    box0.xMax = box1.xMax;
  }
  if(box1.yMin < box0.yMin)
  {
    box0.yMin = box1.yMin;
  }
  if(box1.yMax > box0.yMax)
  {
    box0.yMax = box1.yMax;
  }
  if(box1.zMin < box0.zMin)
  {
    box0.zMin = box1.zMin;
  }
  if(box1.zMax > box0.zMax)
  {
    box0.zMax = box1.zMax;
  }
  return(box0);
}

/*!
* \return	Axis alligned 3D float precision bounding box.
* \ingroup	WlzFeatures
* \brief	Computes the 3D single precision bounding box which
*		encloses the given pair of bounding boxes.
* \param	box0			First bounding box.
* \param	box1			Second bounding box.
*/
WlzFBox3	WlzBoundingBoxUnion3F(WlzFBox3 box0, WlzFBox3 box1)
{
  if(box1.xMin < box0.xMin)
  {
    box0.xMin = box1.xMin;
  }
  if(box1.xMax > box0.xMax)
  {
    box0.xMax = box1.xMax;
  }
  if(box1.yMin < box0.yMin)
  {
    box0.yMin = box1.yMin;
  }
  if(box1.yMax > box0.yMax)
  {
    box0.yMax = box1.yMax;
  }
  if(box1.zMin < box0.zMin)
  {
    box0.zMin = box1.zMin;
  }
  if(box1.zMax > box0.zMax)
  {
    box0.zMax = box1.zMax;
  }
  return(box0);
}

/*!
* \return	Axis alligned 3D double precision bounding box.
* \ingroup	WlzFeatures
* \brief	Computes the 3D double precision bounding box which
*		encloses the given pair of bounding boxes.
* \param	box0			First bounding box.
* \param	box1			Second bounding box.
*/
WlzDBox3	WlzBoundingBoxUnion3D(WlzDBox3 box0, WlzDBox3 box1)
{
  if(box1.xMin < box0.xMin)
  {
    box0.xMin = box1.xMin;
  }
  if(box1.xMax > box0.xMax)
  {
    box0.xMax = box1.xMax;
  }
  if(box1.yMin < box0.yMin)
  {
    box0.yMin = box1.yMin;
  }
  if(box1.yMax > box0.yMax)
  {
    box0.yMax = box1.yMax;
  }
  if(box1.zMin < box0.zMin)
  {
    box0.zMin = box1.zMin;
  }
  if(box1.zMax > box0.zMax)
  {
    box0.zMax = box1.zMax;
  }
  return(box0);
}
back to top