<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineAttributesFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkCenterlineAttributesFilter.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:46:43 $
Version:   $Revision: 1.5 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkCenterlineAttributesFilter - Computes the abscissa and parallel transport normal along a centerline.
// .SECTION Description 
// Abscissas are easy to define: they measure the distances along a line. This class generates abscissas relative to the starting point of the centerline and can be offset to a different location at a later time.
// 
// Parallel Transport Normals are used to help construct an osculating reference system along a centerline. We generate a pair of arbitrary normal and binormal orthogonal vectors are generated for the first point along the centerline.  The reference system created by the orthogonal normal, binormal, and tangent vectors is propagated down the centerline by rotating it (in the osculating plane) by an amount equal to the change in orientation of the line tangent between neighboring pairs of points. 

#ifndef __vtkvmtkCenterlineAttributesFilter_h
#define __vtkvmtkCenterlineAttributesFilter_h

#include "vtkPolyDataAlgorithm.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"

class vtkDoubleArray;

class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineAttributesFilter : public vtkPolyDataAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkCenterlineAttributesFilter,vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkCenterlineAttributesFilter* New();

  vtkSetStringMacro(AbscissasArrayName);
  vtkGetStringMacro(AbscissasArrayName);

  vtkSetStringMacro(ParallelTransportNormalsArrayName);
  vtkGetStringMacro(ParallelTransportNormalsArrayName);

  protected:
  vtkvmtkCenterlineAttributesFilter();
  ~vtkvmtkCenterlineAttributesFilter();  

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  void ComputeAbscissas(vtkPolyData* input, vtkDoubleArray* abscissasArray);
  void ComputeParallelTransportNormals(vtkPolyData* input, vtkDoubleArray* parallelTransportNormalsArray);

  char* AbscissasArrayName;
  char* ParallelTransportNormalsArrayName;

  private:
  vtkvmtkCenterlineAttributesFilter(const vtkvmtkCenterlineAttributesFilter&);  // Not implemented.
  void operator=(const vtkvmtkCenterlineAttributesFilter&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBoundaryExtractor.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkPolyDataBoundaryExtractor.cxx,v $
Language:  C++
Date:      $Date: 2006/07/27 08:27:26 $
Version:   $Revision: 1.6 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataBoundaryExtractor.h"
#include "vtkCellArray.h"
#include "vtkPolyData.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkIdList.h"
#include "vtkGenericCell.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkPolyDataBoundaryExtractor);

vtkvmtkPolyDataBoundaryExtractor::vtkvmtkPolyDataBoundaryExtractor()
{
}

int vtkvmtkPolyDataBoundaryExtractor::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkIdList *boundary, *boundaryIds, *cellEdgeNeighbors, *newCell;
  vtkIdType i, j, currentId, firstId, id, newId, id0, id1;
  newId = -1;
  vtkCell* cell;
  bool foundAny, foundNeighbor, done;
  vtkPoints* newPoints;
  vtkCellArray* newLines;
  vtkIdTypeArray* newScalars;

  input->BuildCells();
  input->BuildLinks();

  // Allocate
  boundary = vtkIdList::New();
  boundaryIds = vtkIdList::New();
  cellEdgeNeighbors = vtkIdList::New();
  newCell = vtkIdList::New();
  newPoints = vtkPoints::New();
  newLines = vtkCellArray::New();
  newScalars = vtkIdTypeArray::New();

  // Execute  
  for (i=0; i<input->GetNumberOfCells(); i++)
    {
    cell = input->GetCell(i);
    for (j=0; j<3; j++)
      {
      cellEdgeNeighbors->Initialize();
      id0 = cell->GetEdge(j)->GetPointIds()->GetId(0);
      id1 = cell->GetEdge(j)->GetPointIds()->GetId(1);
      input->GetCellEdgeNeighbors(i,id0,id1,cellEdgeNeighbors);
      if (cellEdgeNeighbors->GetNumberOfIds()==0)
        {
        boundaryIds->InsertUniqueId(id0);
        boundaryIds->InsertUniqueId(id1);
        }
      }
    }

  if (boundaryIds->GetNumberOfIds() == 0)
    {
    output->SetPoints(newPoints);
    output->SetLines(newLines);
    output->GetPointData()->SetScalars(newScalars);
  
    newPoints->Delete();
    newLines->Delete();
    newScalars->Delete();
  
    boundary->Delete();
    boundaryIds->Delete();
    cellEdgeNeighbors->Delete();
    newCell->Delete();

    return 1;
    }

  foundAny = false;
  foundNeighbor = false;
  done = false;
  currentId = -1;
  int loopCount = 0;
  bool isBoundaryEdge;

  while (!done)
    {
    foundAny = false;
    foundNeighbor = false;
                
    for (i=0; i<boundaryIds->GetNumberOfIds(); i++)
      {
      id = boundaryIds->GetId(i);
      if (id!=-1)
        {
        foundAny = true;
        isBoundaryEdge = false;
        if (currentId!=-1 && input->IsEdge(currentId,id))
          {
          cellEdgeNeighbors->Initialize();
          input->GetCellEdgeNeighbors(-1,currentId,id,cellEdgeNeighbors);
          if (cellEdgeNeighbors->GetNumberOfIds() == 1)
            {
            isBoundaryEdge = true;
            }
          }
        if ((currentId==-1) || isBoundaryEdge)
          {
          foundNeighbor = true;
          }

        if (foundNeighbor)
          {
          currentId = id;
          boundary->InsertNextId(currentId);
          boundaryIds->SetId(i,-1);
          break;
          }
        }
      }

    if ( (((!foundNeighbor)&&(foundAny))||(!foundAny)) && (boundary->GetNumberOfIds() > 2))
      {
      newCell->Initialize();
      newCell->SetNumberOfIds(boundary->GetNumberOfIds());
      firstId = newPoints->GetNumberOfPoints();
      for (j=0; j<boundary->GetNumberOfIds(); j++)
        {
        id = boundary->GetId(j);
        newId = newPoints->InsertNextPoint(input->GetPoint(id));
        newCell->SetId(j,newId);
        newScalars->InsertNextValue(id);
        }

      if (input->IsEdge(newId,firstId))
        {
        newCell->InsertNextId(firstId);
        }

      newLines->InsertNextCell(newCell);

      currentId = -1;
      boundary->Initialize();
      }
        
    if (!foundAny)
      {
      done = true;
      }

    loopCount++;
    if (loopCount > 2*boundaryIds->GetNumberOfIds())
      {
      int missing = 0;
      for (int n=0; n<boundaryIds->GetNumberOfIds(); n++)
        {
        if (boundaryIds->GetId(n) != -1)
          {
          missing++;
          }
        }
      vtkErrorMacro(<<"Can't find adjacent point. Bailing out."); 
      done = true;
      }
    }

  output->SetPoints(newPoints);
  output->SetLines(newLines);
  output->GetPointData()->SetScalars(newScalars);

  // Destroy
  newPoints->Delete();
  newLines->Delete();
  newScalars->Delete();

  boundary->Delete();
  boundaryIds->Delete();
  cellEdgeNeighbors->Delete();
  newCell->Delete();

  return 1;
}

void vtkvmtkPolyDataBoundaryExtractor::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyBall.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkPolyBall.cxx,v $
Language:  C++
Date:      $Date: 2005/03/04 11:07:28 $
Version:   $Revision: 1.2 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "vtkvmtkPolyBall.h"
#include "vtkvmtkConstants.h"
#include "vtkPointData.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkPolyBall);

vtkvmtkPolyBall::vtkvmtkPolyBall()
{
  this->Input = NULL;
  this->PolyBallRadiusArrayName = NULL;
  this->LastPolyBallCenterId = -1;
}

vtkvmtkPolyBall::~vtkvmtkPolyBall()
{
  if (this->Input)
    {
    this->Input->Delete();
    this->Input = NULL;
    }

  if (this->PolyBallRadiusArrayName)
    {
    delete[] this->PolyBallRadiusArrayName;
    this->PolyBallRadiusArrayName = NULL;
    }
}

double vtkvmtkPolyBall::EvaluateFunction(double x[3])
{
  double px[3], pr;
  int i;
  double sphereFunctionValue, minSphereFunctionValue;
  vtkDataArray* polyballRadiusArray;

  if (!this->Input)
    {
    vtkErrorMacro("No Input specified!");
    return 0.0;
    }

  if (this->Input->GetNumberOfPoints()==0)
    {
    vtkWarningMacro("Empty Input specified!");
    }

  if (!this->PolyBallRadiusArrayName)
    {
    vtkErrorMacro("No PolyBallRadiusArrayName specified!");
    return 0.0;
    }

  if (!this->Input->GetPointData()->GetArray(this->PolyBallRadiusArrayName))
    {
    vtkErrorMacro("PolyBallRadiusArray with name specified does not exist!");
    return 0.0;
    }

  polyballRadiusArray = this->Input->GetPointData()->GetArray(this->PolyBallRadiusArrayName);
  minSphereFunctionValue = VTK_VMTK_LARGE_DOUBLE;
  for (i=0; i<this->Input->GetNumberOfPoints(); i++)
    {
    // this next line actually copies the xyz location of point i into px[3].
    // luca reports that odd bug happened when only retrieving pointers.
    this->Input->GetPoint(i,px);
    pr = polyballRadiusArray->GetComponent(i,0);
    // x, y, z -> location of query point in R3
    // px, py, pz => location of point with sphere radius == pr
    // f = ((x - px)^2 + (y - py)^2 + (z - pz)^2) - pr^2
    sphereFunctionValue = ((x[0] - px[0]) * (x[0] - px[0]) + (x[1] - px[1]) * (x[1] - px[1]) + (x[2] - px[2]) * (x[2] - px[2])) - pr*pr;
    if (sphereFunctionValue - minSphereFunctionValue < VTK_VMTK_DOUBLE_TOL)
      {
      minSphereFunctionValue = sphereFunctionValue;
      this->LastPolyBallCenterId = i;
      }
    }

  return minSphereFunctionValue;
}

void vtkvmtkPolyBall::EvaluateGradient(double x[3], double n[3])
{
  vtkWarningMacro("Poly ball gradient computation not implemented yet!");

  // TODO
  //   n[0] = 2.0 * (x[0] - this->Center[0]);
  //   n[1] = 2.0 * (x[1] - this->Center[1]);
  //   n[2] = 2.0 * (x[2] - this->Center[2]);
}

void vtkvmtkPolyBall::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

}


<|start_filename|>vtkVmtk/Segmentation/vtkvmtkITKFilterUtilities.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    vtkvmtkITKFilterUtilities.h
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.2 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

// .NAME vtkvmtkITKFilterUtilities - Abstract class for wrapping ITK filters
// .SECTION Description
// vtkvmtkSimpleImageToImageITKFilter


#ifndef __vtkvmtkITKFilterUtilities_h
#define __vtkvmtkITKFilterUtilities_h

#include "vtkvmtkITKFilterUtilities.h"
#include "vtkvmtkWin32Header.h"

#include "vtkImageData.h"
#include "itkImage.h"
#include "itkCommand.h"

class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkITKFilterUtilities
{
public:

  template<typename TImage>
  static void
  VTKToITKImage(vtkImageData* input, typename TImage::Pointer output) {

    typedef TImage ImageType;
    typedef typename ImageType::Pointer ImagePointer;
    typedef typename ImageType::PixelType PixelType;

    int dims[3];
    input->GetDimensions(dims);
    double spacing[3];
    input->GetSpacing(spacing);
    double origin[3];
    input->GetOrigin(origin);
    int extent[6];
    input->GetExtent(extent);

    output->GetPixelContainer()->SetImportPointer(static_cast<PixelType*>(input->GetScalarPointer()),dims[0]*dims[1]*dims[2],false);
    typename ImageType::RegionType region;
    typename ImageType::IndexType index;
    typename ImageType::SizeType size;
    //index[0] = index[1] = index[2] = 0;
    //size[0] = dims[0];
    //size[1] = dims[1];
    //size[2] = dims[2];
    index[0] = extent[0];
    index[1] = extent[2];
    index[2] = extent[4];
    size[0] = extent[1] - extent[0] + 1;
    size[1] = extent[3] - extent[2] + 1;
    size[2] = extent[5] - extent[4] + 1;
    region.SetIndex(index);
    region.SetSize(size);
    output->SetLargestPossibleRegion(region);
    output->SetBufferedRegion(region);
    output->SetSpacing(spacing);
    output->SetOrigin(origin);
  }

  template<typename TImage>
    static void
    VTKToITKVectorImage(vtkImageData* input, typename TImage::Pointer output) {

    typedef TImage ImageType;
    typedef typename ImageType::Pointer ImagePointer;
    typedef typename ImageType::PixelType PixelType;
    typedef typename ImageType::InternalPixelType InternalPixelType;

    int dims[3];
    input->GetDimensions(dims);
    double spacing[3];
    input->GetSpacing(spacing);
    int components = input->GetNumberOfScalarComponents();
    double origin[3];
    input->GetOrigin(origin);
    int extent[6];
    input->GetExtent(extent);

    output->GetPixelContainer()->SetImportPointer(static_cast<InternalPixelType*>(input->GetScalarPointer()),dims[0]*dims[1]*dims[2]*components,false);
    typename ImageType::RegionType region;
    typename ImageType::IndexType index;
    typename ImageType::SizeType size;
    //index[0] = index[1] = index[2] = 0;
    //size[0] = dims[0];
    //size[1] = dims[1];
    //size[2] = dims[2];
    index[0] = extent[0];
    index[1] = extent[2];
    index[2] = extent[4];
    size[0] = extent[1] - extent[0] + 1;
    size[1] = extent[3] - extent[2] + 1;
    size[2] = extent[5] - extent[4] + 1;
    region.SetIndex(index);
    region.SetSize(size);
    output->SetLargestPossibleRegion(region);
    output->SetBufferedRegion(region);
    output->SetSpacing(spacing);
    output->SetOrigin(origin);
    output->SetVectorLength(components);
  }

  template<typename TImage>
  static void
  ITKToVTKImage(typename TImage::Pointer input, vtkImageData* output) {

    typedef TImage ImageType;
    typedef typename ImageType::Pointer ImagePointer;
    typedef typename ImageType::PixelType PixelType;
    typedef typename ImageType::PointType PointType;
    typedef typename ImageType::SpacingType SpacingType;
    typedef typename ImageType::RegionType RegionType;
    typedef typename ImageType::IndexType IndexType;
    typedef typename ImageType::SizeType SizeType;

    PointType origin = input->GetOrigin();
    SpacingType spacing = input->GetSpacing();

    double outputOrigin[3];
    double outputSpacing[3];
    
    outputOrigin[0] = origin[0];
    outputOrigin[1] = origin[1];
    outputOrigin[2] = origin[2];

    outputSpacing[0] = spacing[0];
    outputSpacing[1] = spacing[1];
    outputSpacing[2] = spacing[2];

    output->SetOrigin(outputOrigin);
    output->SetSpacing(outputSpacing);

    RegionType region = input->GetBufferedRegion();
    IndexType index = region.GetIndex();
    SizeType size = region.GetSize();

    //int dimensions[3];
    //dimensions[0] = size[0];
    //dimensions[1] = size[1];
    //dimensions[2] = size[2];
    int extent[6];
    extent[0] = index[0];
    extent[1] = index[0] + size[0] - 1;
    extent[2] = index[1];
    extent[3] = index[1] + size[1] - 1;
    extent[4] = index[2];
    extent[5] = index[2] + size[2] - 1;

    int components = input->GetNumberOfComponentsPerPixel();
    int dataType = output->GetScalarType(); // WARNING: we delegate setting type to caller

    //output->SetDimensions(dimensions);
    output->SetExtent(extent);
    output->AllocateScalars(dataType,components);

    memcpy(static_cast<PixelType*>(output->GetScalarPointer()),input->GetBufferPointer(),input->GetBufferedRegion().GetNumberOfPixels()*sizeof(PixelType));
  }

  static void
  ProgressCallback(itk::Object *o, const itk::EventObject &, void *data)
  {
    ((vtkAlgorithm*)data)->UpdateProgress(dynamic_cast<const itk::ProcessObject*>(o)->GetProgress());
  }

  static void
  ConnectProgress(itk::Object* obj, vtkAlgorithm* alg)
  {
    itk::CStyleCommand::Pointer progressCommand = itk::CStyleCommand::New();
    progressCommand->SetCallback(vtkvmtkITKFilterUtilities::ProgressCallback);
    progressCommand->SetClientData(alg);
    obj->AddObserver(itk::ProgressEvent(),progressCommand);
  }

protected:
  vtkvmtkITKFilterUtilities() {};
  ~vtkvmtkITKFilterUtilities() {};

private:
  vtkvmtkITKFilterUtilities(const vtkvmtkITKFilterUtilities&);  // Not implemented.
  void operator=(const vtkvmtkITKFilterUtilities&);  // Not implemented.
};

#if 0
template< class TInputPixel, class TOutputPixel>
void
vtkvmtkSimpleImageToImageITKFilter<TInputPixel,TOutputPixel>::
SimpleExecute(vtkImageData *input, vtkImageData *output)
{
  int inputDims[3];
  input->GetDimensions(inputDims);
  double inputSpacing[3];
  input->GetSpacing(inputSpacing);

  InputImagePointer inImage = InputImageType::New();
  inImage->GetPixelContainer()->SetImportPointer(static_cast<InputPixelType*>(input->GetScalarPointer()),inputDims[0]*inputDims[1]*inputDims[2],false);
  typename InputImageType::RegionType inputRegion;
  typename InputImageType::IndexType inputIndex;
  typename InputImageType::SizeType inputSize;
  inputIndex[0] = inputIndex[1] = inputIndex[2] = 0;
  inputSize[0] = inputDims[0];
  inputSize[1] = inputDims[1];
  inputSize[2] = inputDims[2];
  inputRegion.SetIndex(inputIndex);
  inputRegion.SetSize(inputSize);
  inImage->SetLargestPossibleRegion(inputRegion);
  inImage->SetBufferedRegion(inputRegion);
  inImage->SetSpacing(inputSpacing);

  int outputDims[3];
  output->GetDimensions(outputDims);
  double outputSpacing[3];
  output->GetSpacing(outputSpacing);

  OutputImagePointer outImage = OutputImageType::New();
  outImage->GetPixelContainer()->SetImportPointer(static_cast<OutputPixelType*>(output->GetScalarPointer()),outputDims[0]*outputDims[1]*outputDims[2],false);
  typename OutputImageType::RegionType outputRegion;
  typename OutputImageType::IndexType outputIndex;
  typename OutputImageType::SizeType outputSize;
  outputIndex[0] = outputIndex[1] = outputIndex[2] = 0;
  outputSize[0] = outputDims[0];
  outputSize[1] = outputDims[1];
  outputSize[2] = outputDims[2];
  outputRegion.SetIndex(outputIndex);
  outputRegion.SetSize(outputSize);
  outImage->SetLargestPossibleRegion(outputRegion);
  outImage->SetBufferedRegion(outputRegion);
  outImage->SetSpacing(outputSpacing);

  this->SimpleExecuteITK(inImage,outImage);

  memcpy(static_cast<OutputPixelType*>(output->GetScalarPointer()),outImage->GetBufferPointer(),outImage->GetBufferedRegion().GetNumberOfPixels()*sizeof(OutputPixelType));
}

typedef vtkvmtkSimpleImageToImageITKFilter<float,float> vtkvmtkSimpleImageToImageITKFilterFF;
#endif

#endif



<|start_filename|>vtkVmtk/Segmentation/vtkvmtkSatoVesselnessMeasureImageFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkSatoVesselnessMeasureImageFilter.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.2 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

// .NAME vtkvmtkSatoVesselnessMeasureImageFilter - Wrapper class around itk::SatoVesselnessMeasureImageFilter
// .SECTION Description
// vtkvmtkSatoVesselnessMeasureImageFilter


#ifndef __vtkvmtkSatoVesselnessMeasureImageFilter_h
#define __vtkvmtkSatoVesselnessMeasureImageFilter_h

#include "vtkSimpleImageToImageFilter.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkSatoVesselnessMeasureImageFilter : public vtkSimpleImageToImageFilter
{
 public:
  static vtkvmtkSatoVesselnessMeasureImageFilter *New();
  vtkTypeMacro(vtkvmtkSatoVesselnessMeasureImageFilter, vtkSimpleImageToImageFilter);

  vtkGetMacro(SigmaMin,double);
  vtkSetMacro(SigmaMin,double);

  vtkGetMacro(SigmaMax,double);
  vtkSetMacro(SigmaMax,double);

  vtkGetMacro(NumberOfSigmaSteps,int);
  vtkSetMacro(NumberOfSigmaSteps,int);

  vtkGetMacro(SigmaStepMethod,int);
  vtkSetMacro(SigmaStepMethod,int);
  void SetSigmaStepMethodToEquispaced()
  {
    this->SetSigmaStepMethod(EQUISPACED);
  }
  
  void SetSigmaStepMethodToLogarithmic()
  {
    this->SetSigmaStepMethod(LOGARITHMIC);
  }

  vtkGetMacro(Alpha1,double);
  vtkSetMacro(Alpha1,double);

  vtkGetMacro(Alpha2,double);
  vtkSetMacro(Alpha2,double);
//BTX
  enum 
  {
    EQUISPACED,
    LOGARITHMIC
  };
//ETX
protected:
  vtkvmtkSatoVesselnessMeasureImageFilter();
  ~vtkvmtkSatoVesselnessMeasureImageFilter();

  virtual void SimpleExecute(vtkImageData* input, vtkImageData* output) VTK_OVERRIDE;

private:
  vtkvmtkSatoVesselnessMeasureImageFilter(const vtkvmtkSatoVesselnessMeasureImageFilter&);  // Not implemented.
  void operator=(const vtkvmtkSatoVesselnessMeasureImageFilter&);  // Not implemented.

  double SigmaMin;
  double SigmaMax;
  int NumberOfSigmaSteps;
  int SigmaStepMethod;
  double Alpha1;
  double Alpha2;
};

#endif






<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataFELaplaceAssembler.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkPolyDataFELaplaceAssembler.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:44 $
  Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkPolyDataFELaplaceAssembler - construct a laplacian based finite element calculation on a surface.
// .SECTION Description
// ..

#ifndef __vtkvmtkPolyDataFELaplaceAssembler_h
#define __vtkvmtkPolyDataFELaplaceAssembler_h

#include "vtkvmtkFEAssembler.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataFELaplaceAssembler : public vtkvmtkFEAssembler
{
public:

  static vtkvmtkPolyDataFELaplaceAssembler* New();
  vtkTypeMacro(vtkvmtkPolyDataFELaplaceAssembler,vtkvmtkFEAssembler);

  virtual void Build() VTK_OVERRIDE;

protected:
  vtkvmtkPolyDataFELaplaceAssembler();
  ~vtkvmtkPolyDataFELaplaceAssembler();

private:
  vtkvmtkPolyDataFELaplaceAssembler(const vtkvmtkPolyDataFELaplaceAssembler&);  // Not implemented.
  void operator=(const vtkvmtkPolyDataFELaplaceAssembler&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Segmentation/itkFWHMFeatureImageFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: itkFWHMFeatureImageFilter.h,v $
Language:  C++
Date:      $Date: 2005/03/04 11:14:37 $
Version:   $Revision: 1.2 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#ifndef __itkFWHMFeatureImageFilter_h
#define __itkFWHMFeatureImageFilter_h

#include "itkImageToImageFilter.h"
#include "itkImage.h"
#include "itkBinaryBallStructuringElement.h"

namespace itk
{
/** \class FWHMFeatureImageFilter
 * \brief Builds a feature image which allows to perform FWHM level sets segmentation.
 *
 */
template <typename TInputImage, typename TOutputImage>
class FWHMFeatureImageFilter :
    public ImageToImageFilter< TInputImage, TOutputImage >
{
public:
  /** Standard class typedefs. */
  typedef FWHMFeatureImageFilter Self;
  typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass;
  typedef SmartPointer<Self> Pointer;
  typedef SmartPointer<const Self>  ConstPointer;

  /** Method for creation through the object factory. */
  itkNewMacro(Self);

  /** Run-time type information (and related methods) */
  itkTypeMacro(FWHMFeatureImageFilter, ImageToImageFilter);
  
  /** Extract some information from the image types.  Dimensionality
   * of the two images is assumed to be the same. */
  typedef typename TOutputImage::PixelType OutputPixelType;
  typedef typename TInputImage::PixelType InputPixelType;
  typedef typename NumericTraits<InputPixelType>::RealType RealType;

  /** Extract some information from the image types.  Dimensionality
   * of the two images is assumed to be the same. */
  itkStaticConstMacro(ImageDimension, unsigned int,
                      TOutputImage::ImageDimension);
  
  /** Image typedef support */
  typedef TInputImage  InputImageType;
  typedef TOutputImage OutputImageType;
  typedef typename InputImageType::Pointer InputImagePointer;
  typedef typename OutputImageType::Pointer OutputImagePointer;
  
  /** Superclass typedefs. */
  typedef typename Superclass::OutputImageRegionType OutputImageRegionType;

  /** StructuringElement typedefs. */
  typedef itk::BinaryBallStructuringElement<InputPixelType,3> StructuringElementType;

  /** StructuringElementRadius typedefs. */
  typedef typename StructuringElementType::RadiusType StructuringElementRadiusType;

  /** Use the image spacing information in calculations. 
      Default is UseImageSpacingOn. */
  void SetUseImageSpacingOn()
  { this->SetUseImageSpacing(true); }
  
  /** Ignore the image spacing. Use this option if you want calculations to be 
      performed in an isotropic pixel space.  Default is UseImageSpacingOn. */
  void SetUseImageSpacingOff()
  { this->SetUseImageSpacing(false); }
  
  /** Set/Get whether or not the filter will use the spacing of the input
      image in its calculations */
  itkSetMacro(UseImageSpacing, bool);
  itkGetMacro(UseImageSpacing, bool);

  /** Set/Get the structuring element radius */
  itkSetMacro(Radius, StructuringElementRadiusType);
  itkGetMacro(Radius, StructuringElementRadiusType);

  /** Set/Get the background value used to determine the half maximum */
  itkSetMacro(BackgroundValue, InputPixelType);
  itkGetMacro(BackgroundValue, InputPixelType);

protected:
  FWHMFeatureImageFilter();
  virtual ~FWHMFeatureImageFilter() {}

  void GenerateData() ITK_OVERRIDE;

  void PrintSelf(std::ostream&, Indent) const ITK_OVERRIDE;
  
private:
  FWHMFeatureImageFilter(const Self&); //purposely not implemented
  void operator=(const Self&); //purposely not implemented

  bool m_UseImageSpacing;
  StructuringElementRadiusType m_Radius;
  InputPixelType m_BackgroundValue;
};
  
} // end namespace itk

#ifndef ITK_MANUAL_INSTANTIATION
#include "itkFWHMFeatureImageFilter.txx"
#endif

#endif


<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkSparseMatrix.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkSparseMatrix.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:44 $
  Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkSparseMatrix - Class for constructing sparse matrices from a dataset and performing basic mathematical operations on it. 
// .SECTION Description
// ..

#ifndef __vtkvmtkSparseMatrix_h
#define __vtkvmtkSparseMatrix_h

#include "vtkObject.h"
#include "vtkvmtkSparseMatrixRow.h"
#include "vtkvmtkNeighborhoods.h"
#include "vtkvmtkStencils.h"
#include "vtkvmtkDoubleVector.h"
#include "vtkDataSet.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkSparseMatrix : public vtkObject
{
public:

  static vtkvmtkSparseMatrix* New();
  vtkTypeMacro(vtkvmtkSparseMatrix,vtkObject);

  void Multiply(vtkvmtkDoubleVector* x, vtkvmtkDoubleVector* y);
  void TransposeMultiply(vtkvmtkDoubleVector* x, vtkvmtkDoubleVector* y);

  // Description:
  // Get a row given a row id.
  vtkvmtkSparseMatrixRow* GetRow(vtkIdType i) { return this->Array[i]; }

  vtkGetMacro(NumberOfRows,vtkIdType);
  void CopyRowsFromStencils(vtkvmtkStencils *stencils);
  void AllocateRowsFromNeighborhoods(vtkvmtkNeighborhoods *neighborhoods, int numberOfVariables=1);
  void AllocateRowsFromDataSet(vtkDataSet *dataSet, int numberOfVariables=1);
  
  void Initialize();
  void SetNumberOfRows(vtkIdType numberOfRows);

  double GetElement(vtkIdType i, vtkIdType j);
  void SetElement(vtkIdType i, vtkIdType j, double value);
  void AddElement(vtkIdType i, vtkIdType j, double value);

  void DeepCopy(vtkvmtkSparseMatrix *src);

protected:
  vtkvmtkSparseMatrix();
  ~vtkvmtkSparseMatrix();

  vtkvmtkSparseMatrixRow** Array;
  vtkIdType NumberOfRows;

private:
  vtkvmtkSparseMatrix(const vtkvmtkSparseMatrix&);  // Not implemented.
  void operator=(const vtkvmtkSparseMatrix&);  // Not implemented.
};

#endif



<|start_filename|>doc/joss-paper/codemeta.json<|end_filename|>
{
  "@context": "https://raw.githubusercontent.com/codemeta/codemeta/master/codemeta.jsonld",
  "@type": "Code",
  "author": [
    {
      "@id": "https://orcid.org/0000-0002-8367-227X",
      "@type": "Person",
      "email": "<EMAIL>",
      "name": "<NAME>",
      "affiliation": "Orobix Srl."
    },
    {
      "@id": "https://orcid.org/0000-0003-4350-659X",
      "@type": "Person",
      "email": "<EMAIL>",
      "name": "<NAME>",
      "affiliation": "Orobix Srl."
    },
    {
      "@id": "https://orcid.org/0000-0002-7963-1168",
      "@type": "Person",
      "email": "<EMAIL>",
      "name": "<NAME>",
      "affiliation": "University of Toronto"
    },
    {
      "@id": "https://orcid.org/0000-0002-0811-6513",
      "@type": "Person",
      "email": "<EMAIL>",
      "name": "<NAME>",
      "affiliation": "University at Buffalo"
    }
  ],
  "identifier": "",
  "codeRepository": "https://github.com/vmtk/vmtk",
  "datePublished": "2018-04-23",
  "dateModified": "2018-04-23",
  "dateCreated": "2018-04-23",
  "description": "The Vascular Modeling Toolkit is a collection of libraries and tools for 3D reconstruction, geometric analysis, mesh generation and surface data analysis for image-based modeling of blood vessels.",
  "keywords": "vascular modeling, image processing, medical imaging, image segmentation, computational geometry, surface extraction, CFD meshing, hemodynamics, mesh generation, python, c++, centerline",
  "license": "BSD",
  "title": "The Vascular Modeling Toolkit",
  "version": "v1.4.0"
}

<|start_filename|>vtkVmtk/Rendering/vtkvmtkInteractorStyleTrackballCamera.h<|end_filename|>
/*=========================================================================

Program:   VMTK 
Module:    vtkvmtkInteractorStyleTrackballCamera
Language:  C++
Date:      $Date: 2006/07/17 09:52:56 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkInteractorStyleTrackballCamera - use the trackball camera style for 3d user ineteraction
// .SECTION Description
// ...

#ifndef __vtkvmtkInteractorStyleTrackballCamera_h
#define __vtkvmtkInteractorStyleTrackballCamera_h

#include "vtkInteractorStyleTrackballCamera.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_RENDERING_EXPORT vtkvmtkInteractorStyleTrackballCamera : public vtkInteractorStyleTrackballCamera
{
public:
  static vtkvmtkInteractorStyleTrackballCamera *New();

  vtkTypeMacro(vtkvmtkInteractorStyleTrackballCamera,vtkInteractorStyleTrackballCamera);
  //void PrintSelf(ostream& os, vtkIndent indent);

protected:

  vtkvmtkInteractorStyleTrackballCamera() {};
  ~vtkvmtkInteractorStyleTrackballCamera() {};

  virtual void OnChar() VTK_OVERRIDE;

private:
  vtkvmtkInteractorStyleTrackballCamera(const vtkvmtkInteractorStyleTrackballCamera&);  //Not implemented
  void operator=(const vtkvmtkInteractorStyleTrackballCamera&);  //Not implemented
};

#endif


<|start_filename|>vtkVmtk/Segmentation/vtkvmtkMedialCurveFilter.cxx<|end_filename|>
/*=========================================================================

Original Method Developed By:
	Copyright : (C)opyright (Pompeu Fabra University) 2007++
				See COPYRIGHT statement in top level directory.
	Authors   : <NAME> && <NAME>
	Modified  : $Author: $
	Purpose   : Application for computing of medial curve inside a surface
				from the distance map representation of a surface.
	Date      : $Date: $
	Version   : $Revision: $

Modifications Made To Support Integration Into:
	The Vascular Modeling Toolkit (VMTK)
	www.vmtk.org

Modification Authors:
	<NAME>
		University at Buffalo
		Github: rlizzo
		Date: April 12, 2018
	<NAME>
		Orobix Srl.
		Github: lantiga
		Date: April 12, 2018

=========================================================================*/

#include "vtkvmtkMedialCurveFilter.h"
#include "vtkSimpleImageToImageFilter.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"
#include "vtkSmartPointer.h"

#include "vtkvmtkITKFilterUtilities.h"

#include "itkImage.h"
#include "itkRecursiveGaussianImageFilter.h"
#include "itkGradientImageFilter.h"
#include "itkAverageOutwardFluxImageFilter.h"
#include "itkMedialCurveImageFilter.h"
#include "itkApproximateSignedDistanceMapImageFilter.h"

vtkStandardNewMacro(vtkvmtkMedialCurveFilter);

vtkvmtkMedialCurveFilter::vtkvmtkMedialCurveFilter()
{
	this->Sigma = 0.5;
	this->Threshold = 0.0;
}

vtkvmtkMedialCurveFilter::~vtkvmtkMedialCurveFilter() {}


void vtkvmtkMedialCurveFilter::SimpleExecute(vtkImageData* input, vtkImageData* output)
{
	typedef itk::Image<unsigned char, 3> UnsignedCharImageType;
	typedef itk::Image<float, 3> FloatImageType;
	typedef float PixelType;
	typedef itk::Image<PixelType, 3> ImageType;

    UnsignedCharImageType::Pointer inImage = UnsignedCharImageType::New();

    vtkvmtkITKFilterUtilities::VTKToITKImage<UnsignedCharImageType>(input,inImage); 

	typedef itk::ApproximateSignedDistanceMapImageFilter<UnsignedCharImageType, FloatImageType> ApproximateSignedDistanceMapImageFilterType;
	ApproximateSignedDistanceMapImageFilterType::Pointer approximateSignedDistanceMapImageFilter = ApproximateSignedDistanceMapImageFilterType::New();
	approximateSignedDistanceMapImageFilter->SetInput(inImage);
	approximateSignedDistanceMapImageFilter->SetInsideValue(255);
	approximateSignedDistanceMapImageFilter->SetOutsideValue(0);

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 1.	Compute the associated average outward flux
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// To have a good quality gradient of the distance map, perform a light smooth over it. Define
	// convolution kernels in each direction and use them recursively.
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	typedef itk::RecursiveGaussianImageFilter<ImageType, ImageType> RecursiveGaussianFilterType;
	RecursiveGaussianFilterType::Pointer gaussianFilterX = RecursiveGaussianFilterType::New();
	RecursiveGaussianFilterType::Pointer gaussianFilterY = RecursiveGaussianFilterType::New();
	RecursiveGaussianFilterType::Pointer gaussianFilterZ = RecursiveGaussianFilterType::New();

	gaussianFilterX->SetDirection(0);
	gaussianFilterY->SetDirection(1);
	gaussianFilterZ->SetDirection(2);

	gaussianFilterX->SetOrder(RecursiveGaussianFilterType::ZeroOrder);
	gaussianFilterY->SetOrder(RecursiveGaussianFilterType::ZeroOrder);
	gaussianFilterZ->SetOrder(RecursiveGaussianFilterType::ZeroOrder);

	gaussianFilterX->SetNormalizeAcrossScale(false);
	gaussianFilterY->SetNormalizeAcrossScale(false);
	gaussianFilterZ->SetNormalizeAcrossScale(false);

	gaussianFilterX->SetInput(approximateSignedDistanceMapImageFilter->GetOutput());
	gaussianFilterY->SetInput(gaussianFilterX->GetOutput());
	gaussianFilterZ->SetInput(gaussianFilterY->GetOutput());

	gaussianFilterX->SetSigma(this->Sigma);
	gaussianFilterY->SetSigma(this->Sigma);
	gaussianFilterZ->SetSigma(this->Sigma);

	// Compute the gradient.
	typedef itk::GradientImageFilter<ImageType, PixelType, PixelType> GradientFilterType;
	GradientFilterType::Pointer gradientFilter = GradientFilterType::New();
	gradientFilter->SetInput(gaussianFilterZ->GetOutput());
	gradientFilter->SetInput(gaussianFilterY->GetOutput());

	// Compute the average outward flux.
	typedef itk::AverageOutwardFluxImageFilter<ImageType, PixelType, GradientFilterType::OutputImageType::PixelType> AOFFilterType;
	AOFFilterType::Pointer aofFilter = AOFFilterType::New();
	aofFilter->SetInput(approximateSignedDistanceMapImageFilter->GetOutput());
	aofFilter->SetGradientImage(gradientFilter->GetOutput());

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 2. Compute the skeleton
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	typedef itk::MedialCurveImageFilter<ImageType> MedialCurveFilter;
	MedialCurveFilter::Pointer medialFilter = MedialCurveFilter::New();
	medialFilter->SetInput(approximateSignedDistanceMapImageFilter->GetOutput());
	medialFilter->SetAverageOutwardFluxImage(aofFilter->GetOutput());
	medialFilter->SetThreshold(this->Threshold);
	medialFilter->Update();

	vtkvmtkITKFilterUtilities::ITKToVTKImage<UnsignedCharImageType>(medialFilter->GetOutput(),output);
}

<|start_filename|>vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKUtility.h<|end_filename|>
/*=========================================================================

  Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.

  See Doc/copyright/copyright.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  Program:   vtkvmtkITK
  Module:    $HeadURL: http://www.na-mic.org/svn/Slicer3/trunk/Libs/vtkvmtkITK/vtkvmtkITKUtility.h $
  Date:      $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $
  Version:   $Revision: 1900 $

==========================================================================*/

#ifndef __vtkvmtkITKUtility_h
#define __vtkvmtkITKUtility_h


#include "vtkObjectFactory.h"
#include "vtkSetGet.h"

/**
 * This function will connect the given itk::VTKImageExport filter to
 * the given vtkImageImport filter.
 */
template <typename ITK_Exporter, typename VTK_Importer>
void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer)
{
  importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback());
  importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback());
  importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback());
  importer->SetSpacingCallback(exporter->GetSpacingCallback());
  importer->SetOriginCallback(exporter->GetOriginCallback());
  importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback());
  importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback());
  importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback());
  importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback());
  importer->SetDataExtentCallback(exporter->GetDataExtentCallback());
  importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback());
  importer->SetCallbackUserData(exporter->GetCallbackUserData());
}

/**
 * This function will connect the given vtkImageExport filter to
 * the given itk::VTKImageImport filter.
 */
template <typename VTK_Exporter, typename ITK_Importer>
void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer)
{
  importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback());
  importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback());
  importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback());
  importer->SetSpacingCallback(exporter->GetSpacingCallback());
  importer->SetOriginCallback(exporter->GetOriginCallback());
  importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback());
  importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback());
  importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback());
  importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback());
  importer->SetDataExtentCallback(exporter->GetDataExtentCallback());
  importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback());
  importer->SetCallbackUserData(exporter->GetCallbackUserData());
}


#define DelegateSetMacro(name,arg) DelegateITKInputMacro(Set##name,arg)
#define DelegateITKInputMacro(name,arg) \
if ( 1 ) { \
  vtkDebugMacro( << this->GetClassName() << " (" << this << "): setting " #name " to " << #arg ); \
  ImageFilterType* tempFilter = dynamic_cast<ImageFilterType*> ( this->m_Filter.GetPointer() ); \
  if ( tempFilter ) \
    { \
    tempFilter->name ( arg ); \
    this->Modified(); \
    } \
  }

#define DelegateSetMacro2(name,arg1,arg2) DelegateITKInputMacro2(Set##name,arg1,arg2)
#define DelegateITKInputMacro2(name,arg1,arg2) \
if ( 1 ) { \
  vtkDebugMacro( << this->GetClassName() << " (" << this << "): setting " #name " to " << #arg1 ); \
  ImageFilterType* tempFilter = dynamic_cast<ImageFilterType*> ( this->m_Filter.GetPointer() ); \
  if ( tempFilter ) \
    { \
    tempFilter->name ( arg1, arg2 ); \
    this->Modified(); \
    } \
  }

#define DelegateGetMacro(name) DelegateITKOutputMacro (Get##name)
#define DelegateITKOutputMacro(name) \
if ( 1 ) { \
  vtkDebugMacro(<< this->GetClassName() << " (" << this << "): returning " #name ); \
  ImageFilterType* tempFilter = dynamic_cast<ImageFilterType*> ( this->m_Filter.GetPointer() ); \
  if ( tempFilter ) \
    { \
    return tempFilter->name (); \
    } \
    else \
    { \
    vtkErrorMacro ( << this->GetClassName() << " Error getting " #name " Dynamic cast returned 0" ); \
    return 0; \
    } \
  }


// struct vtkvmtkITKProgressDisplay
// {
//   ProgressDisplay(vtkObject* obj, itk::ProcessObject* process): m_Process(process), m_Object(obj) {}
  
//   void Display()
//   {
//     m_Object->SetProgress ( m_Process->GetProgress() );
//     }
  
//   itk::ProcessObject::Pointer m_Process;
//   vtkObject* m_Object();
// };

//   // Add a progress observer for the itk::CurvatureFlowImageFilter.
//   // This will make it clear when this part of the ITK pipeline
//   // executes.
//   ProgressDisplay progressDisplay(denoiser);
//   itk::SimpleMemberCommand<ProgressDisplay>::Pointer progressEvent =
//     itk::SimpleMemberCommand<ProgressDisplay>::New();
//   progressEvent->SetCallbackFunction(&progressDisplay,
//                                      &ProgressDisplay::Display);
//   denoiser->AddObserver(itk::ProgressEvent(), progressEvent);



#endif


<|start_filename|>vtkVmtk/Segmentation/vtkvmtkLaplacianSegmentationLevelSetImageFilter.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkbvsLaplacianSegmentationLevelSetImageFilter.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkLaplacianSegmentationLevelSetImageFilter.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkITKFilterUtilities.h"

#include "itkLaplacianSegmentationLevelSetImageFilter.h"

vtkStandardNewMacro(vtkvmtkLaplacianSegmentationLevelSetImageFilter);

vtkvmtkLaplacianSegmentationLevelSetImageFilter::vtkvmtkLaplacianSegmentationLevelSetImageFilter()
{
  this->IsoSurfaceValue = 0.0;
  this->NumberOfIterations = 0;
  this->PropagationScaling = 0.0;
  this->CurvatureScaling = 0.0;
  this->AdvectionScaling = 0.0;
  this->MaximumRMSError = 1E-6;
  this->UseNegativeFeatures = 0;
  this->AutoGenerateSpeedAdvection = 1;
  this->InterpolateSurfaceLocation = 1;
  this->UseImageSpacing = 1;
  this->RMSChange = 0.0;
  this->ElapsedIterations = 0;
  this->FeatureImage = NULL;
  this->SpeedImage = NULL;
}

vtkvmtkLaplacianSegmentationLevelSetImageFilter::~vtkvmtkLaplacianSegmentationLevelSetImageFilter()
{
  if (this->FeatureImage)
    {
      this->FeatureImage->Delete();
      this->FeatureImage = NULL;
    }
  if (this->SpeedImage)
    {
      this->SpeedImage->Delete();
      this->SpeedImage = NULL;
    }
}

void vtkvmtkLaplacianSegmentationLevelSetImageFilter::SimpleExecute(vtkImageData* input, vtkImageData* output)
{
  typedef itk::Image<float,3> ImageType;

  ImageType::Pointer inImage = ImageType::New();

  vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(input,inImage);

  typedef itk::LaplacianSegmentationLevelSetImageFilter<ImageType,ImageType> LevelSetFilterType;

  ImageType::Pointer featureImage = ImageType::New();
  ImageType::Pointer speedImage = ImageType::New();

  LevelSetFilterType::Pointer levelSetFilter = LevelSetFilterType::New();
  levelSetFilter->SetInput(inImage);
  if (this->FeatureImage)
  {
    vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(this->FeatureImage,featureImage);
    levelSetFilter->SetFeatureImage(featureImage);
  }
  if (this->SpeedImage)
  {
    vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(this->SpeedImage,speedImage);
    levelSetFilter->SetSpeedImage(speedImage);
  }
  levelSetFilter->SetIsoSurfaceValue(this->IsoSurfaceValue);
  levelSetFilter->SetNumberOfIterations(this->NumberOfIterations);
  levelSetFilter->SetPropagationScaling(this->PropagationScaling);
  levelSetFilter->SetCurvatureScaling(this->CurvatureScaling);
  levelSetFilter->SetAdvectionScaling(this->AdvectionScaling);
  levelSetFilter->SetMaximumRMSError(this->MaximumRMSError);
  levelSetFilter->SetReverseExpansionDirection(this->UseNegativeFeatures);
  levelSetFilter->SetAutoGenerateSpeedAdvection(this->AutoGenerateSpeedAdvection);
  levelSetFilter->SetInterpolateSurfaceLocation(this->InterpolateSurfaceLocation);
  levelSetFilter->SetUseImageSpacing(this->UseImageSpacing);
  vtkvmtkITKFilterUtilities::ConnectProgress(levelSetFilter,this);
  levelSetFilter->Update();

  this->RMSChange = levelSetFilter->GetRMSChange();
  this->ElapsedIterations = levelSetFilter->GetElapsedIterations();

  vtkvmtkITKFilterUtilities::ITKToVTKImage<ImageType>(levelSetFilter->GetOutput(),output);
}




<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineAbscissaMetricFilter.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkPolyDataCenterlineAbscissaMetricFilter.cxx,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:43 $
  Version:   $Revision: 1.7 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataCenterlineAbscissaMetricFilter.h"
#include "vtkPointData.h"
#include "vtkCellData.h"
#include "vtkDoubleArray.h"
#include "vtkvmtkPolyBallLine.h"
#include "vtkCell.h"
#include "vtkMath.h"
#include "vtkvmtkConstants.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkCenterlineUtilities.h"


vtkStandardNewMacro(vtkvmtkPolyDataCenterlineAbscissaMetricFilter);

vtkvmtkPolyDataCenterlineAbscissaMetricFilter::vtkvmtkPolyDataCenterlineAbscissaMetricFilter() 
{
  this->AbscissasArrayName = NULL;
}

vtkvmtkPolyDataCenterlineAbscissaMetricFilter::~vtkvmtkPolyDataCenterlineAbscissaMetricFilter()
{
  if (this->AbscissasArrayName)
    {
    delete[] this->AbscissasArrayName;
    this->AbscissasArrayName = NULL;
    }
}

void vtkvmtkPolyDataCenterlineAbscissaMetricFilter::EvaluateMetric(vtkIdType pointId, double point[3], vtkIdType groupId, vtkDataArray* metricArray) 
{
  vtkDataArray* centerlineGroupIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineGroupIdsArrayName);
  vtkDataArray* centerlineTractIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineTractIdsArrayName);
  vtkDataArray* blankingArray = this->Centerlines->GetCellData()->GetArray(this->BlankingArrayName);
  vtkDataArray* centerlineIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineIdsArrayName);

  vtkvmtkPolyBallLine* tube = vtkvmtkPolyBallLine::New();
  vtkIdList* centerlineGroupCellIds = vtkIdList::New();

  tube->SetInput(this->Centerlines);
  tube->SetInputCellIds(centerlineGroupCellIds);
  tube->SetUseRadiusInformation(this->UseRadiusInformation);
  if (this->UseRadiusInformation)
    {
    tube->SetPolyBallRadiusArrayName(this->RadiusArrayName);
    }

  double averageAbscissa = 0.0;
  double weightSum = 0.0;

  int numberOfCenterlineCells = this->Centerlines->GetNumberOfCells();
  for (int i=0; i<numberOfCenterlineCells; i++)
    {
    int centerlineGroupId = static_cast<int>(centerlineGroupIdsArray->GetComponent(i,0));
    if (centerlineGroupId != groupId)
      {
      continue;
      }

    centerlineGroupCellIds->Initialize();
    centerlineGroupCellIds->InsertNextId(i);

    if (this->IncludeBifurcations)
      {
      int centerlineId = static_cast<int>(centerlineIdsArray->GetComponent(i,0));
      int centerlineTractId = static_cast<int>(centerlineTractIdsArray->GetComponent(i,0));

      for (int j=0; j<numberOfCenterlineCells; j++)
        {
        if (j==i)
          {
          continue;
          }

        int adjacentCenterlineGroupId = static_cast<int>(centerlineGroupIdsArray->GetComponent(j,0));
        int adjacentCenterlineId = static_cast<int>(centerlineIdsArray->GetComponent(j,0));
        int adjacentCenterlineTractId = static_cast<int>(centerlineTractIdsArray->GetComponent(j,0));
        int adjacentBlanking = static_cast<int>(blankingArray->GetComponent(j,0));
        
        if (adjacentBlanking == 0)
          {
          continue;
          }

        if (adjacentCenterlineGroupId == centerlineGroupId)
          {
          continue;
          }

        if (adjacentCenterlineId != centerlineId)
          {
          continue;
          }
        
        if (!((adjacentCenterlineTractId == centerlineTractId - 1) || 
              (adjacentCenterlineTractId == centerlineTractId + 1)))
          {
          continue;
          }

        centerlineGroupCellIds->InsertNextId(j);
        }
      }

    tube->EvaluateFunction(point);

    vtkIdType centerlineCellId = tube->GetLastPolyBallCellId();
    vtkIdType centerlineSubId = tube->GetLastPolyBallCellSubId();
    double centerlinePCoord = tube->GetLastPolyBallCellPCoord();
    double radius = 0.0;
    vtkvmtkCenterlineUtilities::InterpolateTuple1(this->Centerlines,this->RadiusArrayName,centerlineCellId,centerlineSubId,centerlinePCoord,radius);
    double weight = radius * radius;
    double abscissa = 0.0;
    vtkvmtkCenterlineUtilities::InterpolateTuple1(this->Centerlines,this->AbscissasArrayName,centerlineCellId,centerlineSubId,centerlinePCoord,abscissa);

    averageAbscissa += weight * abscissa;

    weightSum += weight;
    }

  averageAbscissa /= weightSum;

  metricArray->SetComponent(pointId,0,averageAbscissa);

  centerlineGroupCellIds->Delete();
  tube->Delete();
}


<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataFVFELaplaceBeltramiStencil.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkPolyDataFVFELaplaceBeltramiStencil.cxx,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:44 $
  Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataFVFELaplaceBeltramiStencil.h"
#include "vtkvmtkMath.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkConstants.h"


vtkStandardNewMacro(vtkvmtkPolyDataFVFELaplaceBeltramiStencil);

vtkvmtkPolyDataFVFELaplaceBeltramiStencil::vtkvmtkPolyDataFVFELaplaceBeltramiStencil()
{
  this->UseExtendedNeighborhood = 1;
}
  
void vtkvmtkPolyDataFVFELaplaceBeltramiStencil::ComputeArea(vtkPolyData *data, vtkIdType pointId)
  {
  double point[3], point1[3], point2[3];
  vtkIdType j, numberOfTriangles;
  int triangleObtusity;

  data->GetPoint(pointId,point);
  this->Area = 0.0;

  if (!this->IsBoundary)
    numberOfTriangles = this->NPoints;
  else
    numberOfTriangles = this->NPoints-1;

  for (j=0; j<numberOfTriangles; j++)
    {
    data->GetPoint(this->PointIds[j],point1);
    
    data->GetPoint(this->PointIds[(j+1)%this->NPoints],point2);
    
    triangleObtusity = vtkvmtkMath::IsTriangleObtuse(point2,point,point1);
    
    if (triangleObtusity==VTK_VMTK_NON_OBTUSE)
      this->Area += vtkvmtkMath::VoronoiSectorArea(point2,point,point1);
    else if (triangleObtusity==VTK_VMTK_OBTUSE_IN_POINT)
      this->Area += vtkvmtkMath::TriangleArea(point2,point,point1)/2.0;
    else if (triangleObtusity==VTK_VMTK_OBTUSE_NOT_IN_POINT)
      this->Area += vtkvmtkMath::TriangleArea(point2,point,point1)/4.0;
    }
  }

void vtkvmtkPolyDataFVFELaplaceBeltramiStencil::ScaleWithArea()
  {
//  this->ScaleWithAreaFactor(1.0);
  this->ScaleWithAreaFactor(1.0/3.0);
  }




<|start_filename|>vtkVmtk/Segmentation/vtkvmtkGradientMagnitudeImageFilter.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkbvsGradientMagnitudeImageFilter.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkGradientMagnitudeImageFilter.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkITKFilterUtilities.h"

#include "itkGradientMagnitudeImageFilter.h"

vtkStandardNewMacro(vtkvmtkGradientMagnitudeImageFilter);

void vtkvmtkGradientMagnitudeImageFilter::SimpleExecute(vtkImageData* input, vtkImageData* output)
{
  typedef itk::Image<float,3> ImageType;
  ImageType::Pointer inImage = ImageType::New();

  vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(input,inImage);

  typedef itk::GradientMagnitudeImageFilter<ImageType,ImageType> GradientMagnitudeFilterType;

  GradientMagnitudeFilterType::Pointer gradientMagnitudeFilter = GradientMagnitudeFilterType::New();
  gradientMagnitudeFilter->SetInput(inImage);
  gradientMagnitudeFilter->Update();

  vtkvmtkITKFilterUtilities::ITKToVTKImage<ImageType>(gradientMagnitudeFilter->GetOutput(),output);
}



<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineUtilities.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkCenterlineUtilities.h,v $
Language:  C++
Date:      $Date: 2006/10/17 15:16:16 $
Version:   $Revision: 1.5 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkCenterlineUtilities - Collection of functions which are used when working with split and grouped centerlines.
// .SECTION Description
// ...

#ifndef __vtkvmtkCenterlineUtilities_h
#define __vtkvmtkCenterlineUtilities_h

#include "vtkObject.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"

class vtkPolyData;
class vtkPoints;
class vtkIdList;

class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineUtilities : public vtkObject
{
public: 
  vtkTypeMacro(vtkvmtkCenterlineUtilities,vtkObject);
  static vtkvmtkCenterlineUtilities* New(); 

  static vtkIdType GetMaxGroupId(vtkPolyData* centerlines, const char* groupIdsArrayName);
  
  static void GetGroupsIdList(vtkPolyData* centerlines, const char* groupIdsArrayName, vtkIdList* groupIds);
  
  static void GetGroupsIdList(vtkPolyData* centerlines, const char* groupIdsArrayName, const char* blankingArrayName, int blanked, vtkIdList* groupIds);
  
  static void GetNonBlankedGroupsIdList(vtkPolyData* centerlines, const char* groupIdsArrayName, const char* blankingArrayName, vtkIdList* groupIds);
  
  static void GetBlankedGroupsIdList(vtkPolyData* centerlines, const char* groupIdsArrayName, const char* blankingArrayName, vtkIdList* groupIds);

  static void GetGroupCellIds(vtkPolyData* centerlines, const char* groupIdsArrayName, vtkIdType groupId, vtkIdList* groupCellIds);
  
  static void GetGroupUniqueCellIds(vtkPolyData* centerlines, const char* groupIdsArrayName, vtkIdType groupId, vtkIdList* groupCellIds);

  static void GetCenterlineCellIds(vtkPolyData* centerlines, const char* centerlineIdsArrayName, vtkIdType centerlineId, vtkIdList* centerlineCellIds);
  
  static void GetCenterlineCellIds(vtkPolyData* centerlines, const char* centerlineIdsArrayName, const char* tractIdsArrayName, vtkIdType centerlineId, vtkIdList* centerlineCellIds);

  static int IsGroupBlanked(vtkPolyData* centerlines, const char* groupIdsArrayName, const char* blankingArrayName, vtkIdType groupId);
  
  static int IsCellBlanked(vtkPolyData* centerlines, const char* blankingArrayName, vtkIdType cellId);
  
  static void FindAdjacentCenterlineGroupIds(vtkPolyData* centerlines, const char* groupIdsArrayName, const char* centerlineIdsArrayName, const char* tractIdsArrayName, vtkIdType groupId, vtkIdList* upStreamGroupIds, vtkIdList* downStreamGroupIds);

  static void InterpolatePoint(vtkPolyData* centerlines, int cellId, int subId, double pcoord, double interpolatedPoint[3]);

  static void InterpolateTuple(vtkPolyData* centerlines, const char* arrayName, int cellId, int subId, double pcoord, double* interpolatedTuple);

  static void InterpolateTuple1(vtkPolyData* centerlines, const char* arrayName, int cellId, int subId, double pcoord, double& interpolatedTuple1)
  {
    InterpolateTuple(centerlines,arrayName,cellId,subId,pcoord,&interpolatedTuple1);
  }
 
  static void InterpolateTuple3(vtkPolyData* centerlines, const char* arrayName, int cellId, int subId, double pcoord, double interpolatedTuple3[3])
  {
    InterpolateTuple(centerlines,arrayName,cellId,subId,pcoord,interpolatedTuple3);
  }
 
  static void FindMergingPoints(vtkPolyData* centerlines, vtkPoints* mergingPoints, double tolerance);

protected:
  vtkvmtkCenterlineUtilities() {};
  ~vtkvmtkCenterlineUtilities() {};

private:
  vtkvmtkCenterlineUtilities(const vtkvmtkCenterlineUtilities&);  // Not implemented.
  void operator=(const vtkvmtkCenterlineUtilities&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineSmoothing.cxx<|end_filename|>
/*=========================================================================

Program:   VTK Blood Vessel Smoothing
Module:    $RCSfile: vtkvmtkCenterlineSmoothing.cxx,v $
Language:  C++
Date:      $Date: 2006/07/17 09:52:56 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkCenterlineSmoothing.h"
#include "vtkvmtkConstants.h"
#include "vtkPolyData.h"
#include "vtkPointData.h"
#include "vtkCellData.h"
#include "vtkPolyLine.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkCenterlineSmoothing);

vtkvmtkCenterlineSmoothing::vtkvmtkCenterlineSmoothing()
{
  this->SmoothingFactor = 0.01;
  this->NumberOfSmoothingIterations = 100;
}

vtkvmtkCenterlineSmoothing::~vtkvmtkCenterlineSmoothing()
{
}

int vtkvmtkCenterlineSmoothing::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and ouptut
  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  output->DeepCopy(input);

  for (int i=0; i<input->GetNumberOfCells(); i++)
    {
    vtkCell* line = input->GetCell(i);
    if (line->GetCellType() != VTK_LINE && line->GetCellType() != VTK_POLY_LINE)
      {
      continue;
      }
 
    vtkPoints* smoothLinePoints = vtkPoints::New();
    this->SmoothLine(line->GetPoints(),smoothLinePoints,this->NumberOfSmoothingIterations,this->SmoothingFactor);
   
    int numberOfLinePoints = smoothLinePoints->GetNumberOfPoints();

    for (int j=0; j<numberOfLinePoints; j++)
      {
      vtkIdType pointId = line->GetPointId(j);
      output->GetPoints()->SetPoint(pointId,smoothLinePoints->GetPoint(j));
      }

    smoothLinePoints->Delete();
    }

  return 1;
}

void vtkvmtkCenterlineSmoothing::SmoothLine(vtkPoints* linePoints, vtkPoints* smoothLinePoints, int numberOfIterations, double relaxation)
{
  int numberOfPoints = linePoints->GetNumberOfPoints();

  smoothLinePoints->DeepCopy(linePoints);

  double point0[3];
  double point1[3];
  double point2[3];

  for (int i=0; i<numberOfIterations; i++)
    {
    for (int j=1; j<numberOfPoints-1; j++)
      {
      smoothLinePoints->GetPoint(j-1,point0);
      smoothLinePoints->GetPoint(j  ,point1);
      smoothLinePoints->GetPoint(j+1,point2);

      point1[0] += relaxation * (0.5 * (point0[0] + point2[0]) - point1[0]);
      point1[1] += relaxation * (0.5 * (point0[1] + point2[1]) - point1[1]);
      point1[2] += relaxation * (0.5 * (point0[2] + point2[2]) - point1[2]);

      smoothLinePoints->SetPoint(j,point1);
      }
    }
}

void vtkvmtkCenterlineSmoothing::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/Stellar.c<|end_filename|>
/* aggregate Stellar sources in the proper order */
#include "top.c"
#include "interact.c"
#include "vector.c"
#include "anisotropy.c"
#include "quality.c"
#include "arraypoolstack.c"
#include "journal.c"
#include "print.c"
#include "classify.c"
#include "quadric.c"
#include "smoothing.c"
#include "topological.c"
#include "output.c"
#include "insertion.c"
#include "size.c"
#include "improve.c"
#include "main.c"



<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkStencil.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkStencil.cxx,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:44 $
  Version:   $Revision: 1.5 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkStencil.h"
#include "vtkvmtkConstants.h"
#include "vtkObjectFactory.h"



vtkvmtkStencil::vtkvmtkStencil()
  {
  this->Weights = NULL;
  this->CenterWeight = NULL;
  this->NumberOfComponents = 1;
  this->WeightScaling = 1;
  this->NegateWeights = 1;
  }

vtkvmtkStencil::~vtkvmtkStencil()
  {
  if (this->CenterWeight != NULL)
    {
    delete[] this->CenterWeight;
    this->CenterWeight = NULL;
    }

  if (this->Weights != NULL)
    {
    delete[] this->Weights;
    this->Weights = NULL;
    }
  }

void vtkvmtkStencil::ChangeWeightSign()
{
  if (!this->NegateWeights)
    {
    return;
    }
  
  for (int j=0; j<this->NumberOfComponents*this->NPoints; j++)
    {
    this->Weights[j] *= -1.0;
    }
}

void vtkvmtkStencil::ResizePointList(vtkIdType ptId, int size)
  {
  this->Superclass::ResizePointList(ptId,size);

  double *weights;
  
  weights = new double[this->NumberOfComponents*this->NPoints];
  memcpy(weights, this->Weights,this->NumberOfComponents*this->NPoints*sizeof(double));
  delete [] this->Weights;
  this->Weights = weights;
}

void vtkvmtkStencil::ScaleWeights(double factor)
  {
  vtkIdType j;

  if (!this->WeightScaling)
    {
    return;
    }

  if (fabs(factor)<VTK_VMTK_DOUBLE_TOL)
    {
    for (j=0; j<this->NumberOfComponents*this->NPoints; j++)
      {
      this->Weights[j] = 0.0;
      }
    for (j=0; j<this->NumberOfComponents; j++)
      {
      this->CenterWeight[j] = 0.0;
      }
    return;
    }
  else if (fabs(factor)>VTK_VMTK_LARGE_DOUBLE)
    {
    for (j=0; j<this->NumberOfComponents*this->NPoints; j++)
      {
      this->Weights[j] = VTK_VMTK_LARGE_DOUBLE;
      }
    for (j=0; j<this->NumberOfComponents; j++)
      {
      this->CenterWeight[j] = VTK_VMTK_LARGE_DOUBLE;
      }
    return;
    }

  for (j=0; j<this->NumberOfComponents*this->NPoints; j++)
    {
    this->Weights[j] *= factor;
    if (fabs(this->Weights[j])<VTK_VMTK_DOUBLE_TOL)
      {
      this->Weights[j] = 0.0;
      }
    }

  for (j=0; j<this->NumberOfComponents; j++)
    {
    this->CenterWeight[j] *= factor;
    if (fabs(this->CenterWeight[j])<VTK_VMTK_DOUBLE_TOL)
      {
      this->CenterWeight[j] = 0.0;
      }
    }

  }

void vtkvmtkStencil::DeepCopy(vtkvmtkItem *src)
  {
  this->Superclass::DeepCopy(src);

  vtkvmtkStencil* stencilSrc = vtkvmtkStencil::SafeDownCast(src);

  if (stencilSrc==NULL)
    {
    vtkErrorMacro(<<"Trying to deep copy a non-stencil item");
    }

  if (this->CenterWeight != NULL)
    {
    delete[] this->CenterWeight;
    this->CenterWeight = NULL;
    }

  if (this->Weights != NULL)
    {
    delete[] this->Weights;
    this->Weights = NULL;
    }

  this->NumberOfComponents = stencilSrc->NumberOfComponents;

  if (stencilSrc->NPoints>0)
    {
    this->Weights = new double[stencilSrc->NumberOfComponents*stencilSrc->NPoints];
    memcpy(this->Weights, stencilSrc->Weights, this->NumberOfComponents*this->NPoints * sizeof(double));
    }

  this->CenterWeight = new double[stencilSrc->NumberOfComponents];
  memcpy(this->CenterWeight, stencilSrc->CenterWeight, this->NumberOfComponents * sizeof(double));

  this->WeightScaling = stencilSrc->WeightScaling;
  }



<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/improve.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*  driver functions to direct mesh improvement                              */
/*                                                                           */
/*****************************************************************************/

/* see if new means contains any better means. if so,
   update best means and return true */
bool meanimprove(starreal bestmeans[],
                 starreal newmeans[],
                 int passtype)
{
    int i;
    bool foundbetter = false;
    starreal minimprovement = improvebehave.minstepimprovement;
    
    if (passtype == INSERTPASS)
    {
        minimprovement = improvebehave.mininsertionimprovement;
    }
    if (passtype == DESPERATEPASS)
    {
        minimprovement = improvebehave.mininsertionimprovement;
    }
    
    for (i=0; i<NUMMEANTHRESHOLDS; i++)
    {
        if (newmeans[i] > bestmeans[i])
        {
            /* see if it beats it by the required threshold */
            if (newmeans[i] - bestmeans[i] > minimprovement)
            {
                if (improvebehave.verbosity > 4)
                {
                    textcolor(BRIGHT, GREEN, BLACK);
                    printf("mean improvement = %g, that's enough for success (needs %g)\n", newmeans[i] - bestmeans[i], minimprovement);
                    textcolor(RESET, WHITE, BLACK);
                }
                foundbetter = true;
            }
            else
            {
                if (improvebehave.verbosity > 4)
                {
                    printf("mean improvement = %g, positive but not enough (needs %g)!\n", newmeans[i] - bestmeans[i], minimprovement);
                }
            }
            
            bestmeans[i] = newmeans[i];
        }
    }
    
    if (improvebehave.verbosity > 4)
    {
        printf("overall, mean improvement success = %d\n", foundbetter);
    }
    
    return foundbetter;
}

/* run a pass (smoothing, topo, insertion). return true
   if we have reached the desired quality */
bool pass(int passtype,
          struct tetcomplex* mesh,
          struct arraypoolstack* tetstack,
          starreal threshold,
          bool *minsuccess,
          bool *meansuccess,
          int passnum,
          starreal bestmeans[],
          struct behavior *behave,
          struct inputs *in,
          struct proxipool *vertexpool,
          int argc,
          char **argv)
{
    /* quality vars */
    starreal minqualbefore, minqualafter;
    starreal meanqualbefore[NUMMEANTHRESHOLDS], meanqualafter[NUMMEANTHRESHOLDS];
    starreal minedge, maxedge, meanedge;
    
#ifndef NO_TIMER
    /* timing vars */
    struct timeval tv1, tv2;
    struct timezone tz;
#endif /* not NO_TIMER */
    
    /* smoothing vars */
    int smoothkinds = 0;
    
    /* sine of target angles */
    starreal goalangleminsine = degtosin(improvebehave.goalanglemin);
    starreal goalanglemaxsine = degtosin(improvebehave.goalanglemax);
    starreal biggestangle;
    starreal smallestangle;
    
    bool desperate = false;
    int passstartid = 0;
    
    if (improvebehave.facetsmooth) smoothkinds |= SMOOTHFACETVERTICES;
    if (improvebehave.segmentsmooth) smoothkinds |= SMOOTHSEGMENTVERTICES;
    if (improvebehave.fixedsmooth) smoothkinds |= SMOOTHFIXEDVERTICES;
    
    assert(passtype == SMOOTHPASS ||
           passtype == TOPOPASS ||
           passtype == CONTRACTPASS ||
           passtype == CONTRACTALLPASS ||
           passtype == INSERTPASS ||
           passtype == DESPERATEPASS);
    
    if (improvebehave.verbosity > 1)
    {
        textcolor(BRIGHT, MAGENTA, BLACK);
        printf("\nPerforming improvement pass %d", passnum);
        switch (passtype)
        {
            case SMOOTHPASS:
                printf(" (smoothing)\n");
                break;
            case TOPOPASS:
                printf(" (topological)\n");
                break;
            case CONTRACTALLPASS:
            case CONTRACTPASS:
                printf(" (edge contraction)\n");
                break;
            case INSERTPASS:
            case DESPERATEPASS:
                printf(" (insertion)\n");
                break;
            default:
                printf("whoa, I know what kind of pass %d is\n", passtype);
                starexit(1);
        }
        textcolor(RESET, WHITE, BLACK);
    }
           
    /* start out by appropriately filling the stack */
    if (passtype != CONTRACTALLPASS)
    {
        fillstackqual(mesh, tetstack, improvebehave.qualmeasure, threshold, meanqualbefore, &minqualbefore);
    }
    else
    {
        /* in the case of contraction, just get one tet for each edge */
        filledgestacks(mesh, tetstack, NULL, HUGEFLOAT, 0.0, &minedge, &maxedge, &meanedge);
    }
    
    /* get global worst quality; this is what must improve */
    meshquality(mesh, improvebehave.qualmeasure, meanqualbefore, &minqualbefore);
    
    /* if this is the first pass, and we're animating, output original mesh */
    if (improvebehave.animate && passnum == 1)
    {
        outputqualmesh(behave, in, vertexpool, mesh, argc, argv, 0, passtype, 0, QUALMINSINE);
    }
    
    /* capture animation info */
    if (improvebehave.animate)
    {
        passstartid = lastjournalentry(); 
    }
    
    /* save timer before pass */
#ifndef NO_TIMER
    gettimeofday(&tv1, &tz);
#endif /* not NO_TIMER */    

    /* run the actual pass */
    switch (passtype)
    {
        case SMOOTHPASS:
            smoothpass(mesh, 
                       tetstack, 
                       NULL, NULL, 
                       improvebehave.qualmeasure, 
                       threshold, 
                       bestmeans, 
                       meanqualafter, 
                       &minqualafter, 
                       smoothkinds, 
                       false);
#ifndef NO_TIMER
            gettimeofday(&tv2, &tz);
            stats.smoothmsec += msecelapsed(tv1, tv2);
#endif /* not NO_TIMER */
            break;
        case TOPOPASS:
            topopass(mesh, 
                     tetstack, 
                     NULL, 
                     improvebehave.qualmeasure, 
                     bestmeans, 
                     meanqualafter, 
                     &minqualafter, 
                     false);
#ifndef NO_TIMER
            gettimeofday(&tv2, &tz);
            stats.topomsec += msecelapsed(tv1, tv2);
#endif /* not NO_TIMER */
            break;
        case CONTRACTPASS:
            contractworst(mesh, 
                          improvebehave.qualmeasure,
                          improvebehave.insertthreshold, 
                          bestmeans, 
                          meanqualafter, 
                          &minqualafter, 
                          true);
#ifndef NO_TIMER
            gettimeofday(&tv2, &tz);
            stats.contractmsec += msecelapsed(tv1, tv2);
#endif /* not NO_TIMER */
            break;
        case CONTRACTALLPASS:
            contractpass(mesh, 
                         tetstack,
                         NULL,
                         improvebehave.qualmeasure, 
                         bestmeans, 
                         meanqualafter, 
                         &minqualafter, 
                         true,
                         false);
#ifndef NO_TIMER
            gettimeofday(&tv2, &tz);
            stats.contractmsec += msecelapsed(tv1, tv2);
#endif /* not NO_TIMER */
            break;
        case DESPERATEPASS:
            desperate = true;
        case INSERTPASS:
            worsttetattack(mesh, 
                           improvebehave.qualmeasure, 
                           improvebehave.insertthreshold, 
                           meanqualafter, 
                           &minqualafter, 
                           desperate);
#ifndef NO_TIMER
            gettimeofday(&tv2, &tz);
            stats.insertmsec += msecelapsed(tv1, tv2);
# endif /* not NO_TIMER */
            if (desperate)
            {
                *meansuccess = meanimprove(bestmeans, meanqualafter, DESPERATEPASS);
            }
            else
            {
                *meansuccess = meanimprove(bestmeans, meanqualafter, INSERTPASS);
            }
            break;
        default:
            printf("i don't know how to run pass type %d, dying\n", passtype);
            starexit(1);
    }
    
    /* check for success */
    *meansuccess = meanimprove(bestmeans, meanqualafter, passtype);
    if (minqualafter - minqualbefore < MINMINIMPROVEMENT)
    {
        *minsuccess = false;
    }
    else
    {
        *minsuccess = true;
    }
    
    /* output the mesh after this pass, if animating */
    if (improvebehave.animate)
    {
        outputqualmesh(behave, in, vertexpool, mesh, argc, argv, passnum, passtype, passstartid, QUALMINSINE);
    }
    
    /* check whether we have reached the goal quality for minimum or maximum angle */
    if (minqualafter > goalangleminsine || minqualafter > goalanglemaxsine)
    {
        /* compute the extreme angles */
        getextremeangles(behave, mesh, &smallestangle, &biggestangle);
        
        /* we must have reached one of these angles */
        /* not necessarily true for non-angle based quality measures */
        /* assert(smallestangle > improvebehave.goalanglemin || biggestangle < improvebehave.goalanglemax); */
        
        if (improvebehave.verbosity > 3)
        {
            if (smallestangle > improvebehave.goalanglemin)
            {
                printf("Smallest angle %g degrees in ABOVE goal angle of %g degrees\n", smallestangle, improvebehave.goalanglemin);
            }
            else
            {
                printf("Smallest angle %g degrees is BELOW goal angle of %g degrees.\n", smallestangle, improvebehave.goalanglemin);
            }
        
            if (biggestangle < improvebehave.goalanglemax)
            {
                printf("Largest angle %g degrees is BELOW goal angle of %g degrees.\n", biggestangle, improvebehave.goalanglemax);
            }
            else
            {
                printf("Largest angle %g degrees is ABOVE goal angle of %g degrees.\n", biggestangle, improvebehave.goalanglemax);
            }
        }
        
        /* if we've reached both thresholds, let the main loop know we're done */
        if (smallestangle > improvebehave.goalanglemin && biggestangle < improvebehave.goalanglemax)
        {
            if (improvebehave.verbosity > 1)
            {
                textcolor(BRIGHT, GREEN, BLACK);
                printf("Both min and max goal angles reached, stopping improvement.\n");
                textcolor(RESET, WHITE, BLACK);
            }
            return true;
        }
    }
    
    return false;
}

/* pre-improvement initialization code */
void improveinit(struct tetcomplex *mesh,
                 struct proxipool *vertexpool,
                 struct arraypoolstack *tetstack,
                 struct behavior *behave,
                 struct inputs *in,
                 int argc, 
                 char **argv,
                 starreal bestmeans[NUMMEANTHRESHOLDS])
{
    int consistent;
    starreal minqualbefore;
    starreal meanqualbefore[NUMMEANTHRESHOLDS];
    starreal worstin;
    starreal worstinitqual;
    int i;
    
    for (i=0; i<NUMMEANTHRESHOLDS; i++)
    {
        bestmeans[i] = 0.0;
    }
    
    /* assure that the mesh is consistent at the outset */
    consistent = mytetcomplexconsistency(mesh);
    assert(consistent);
    
    stats.startnumverts = countverts(vertexpool);
    stats.startnumtets = counttets(mesh);
    
    /* upon request, just spit out mesh and quit */
    if (improvebehave.outputandquit)
    {
        printf("Outputting mesh and quitting.\n");
        outputqualmesh(behave, in, vertexpool, mesh, argc, argv, 0, SMOOTHPASS, 0, improvebehave.qualmeasure);
        starexit(1);
    }
    
    if (improvebehave.verbosity > 0)
    {
        printf("Improving mesh.\n");
    }
    
    /* this array pool stores information on vertices */
    arraypoolinit(&vertexinfo, sizeof(struct vertextype), LOG2TETSPERSTACKBLOCK, 0);
    
    /* stack of tets to be improved */
    stackinit(tetstack, sizeof(struct improvetet));
    
    /* this stack stores a journal of improvement steps */
    journal = &journalstack;
    stackinit(journal, sizeof(struct journalentry));
    
    /* compute bounding box for anisotropy */
    setboundingbox(mesh);
    
    if (improvebehave.verbosity > 1)
    {
        /* print improvement configuration */
        printimproveoptions(&improvebehave);
        /* print initial mesh statistics before improvement */
        printf("Mesh quality before improvement:\n");
        improvestatistics(behave, mesh, false);
        if (improvebehave.anisotropic)
        {
            printf("Mesh quality before improvement (ISOTROPIC SPACE):\n");
            improvestatistics(behave, mesh, true);
        }
    }
    
    /* print out the worst input angle */
    worstin = worstinputangle(mesh);
    if (improvebehave.verbosity > 2)
    {
        printf("The worst input angle is %g radians (%g degrees).\n", worstin, worstin * (180.0 / PI));
    }
    
    /* classify degrees of freedom of all vertices */
    if (improvebehave.verbosity > 2)
    {
        printf("Performing vertex classification.\n");
    }
    classifyvertices(mesh);
    
    /* compute surface quadric information */
    if (improvebehave.verbosity > 2)
    {
        printf("Computing intial surface quadrics\n");
    }
    collectquadrics(mesh);
    if (improvebehave.verbosity > 2)
    {
        checkquadrics(mesh);
    }
    
    /* make sure that all the tets are right-side out before we start */
    worstinitqual = worstquality(mesh);
    if (worstinitqual <= 0.0)
    {
        textcolor(BRIGHT, RED, BLACK);
        printf("***** ALERT Input mesh has non-positive worst quality of %g, dying *****\n", worstinitqual);
        textcolor(RESET, WHITE, BLACK);
    }
    if (improvebehave.dynimprove)
    {
        assert(worstinitqual > 0.0);
    }
    
    /* build stack for initial quality evaluation */
    fillstackqual(mesh, tetstack, improvebehave.qualmeasure, HUGEFLOAT, meanqualbefore, &minqualbefore);
    meanimprove(bestmeans, meanqualbefore, SMOOTHPASS);
    
    /* set initial minimum and thresholded mean qualities */
    for (i=0; i<NUMMEANTHRESHOLDS; i++)
    {
        stats.startmeanquals[i] = meanqualbefore[i];
    }
    stats.startworstqual = minqualbefore;
    setbeginqual(behave, mesh);
}

/* clean up after mesh improvement */
void improvedeinit(struct tetcomplex *mesh,
                   struct proxipool *vertexpool,
                   struct arraypoolstack *tetstack,
                   struct behavior *behave,
                   struct inputs *in,
                   int argc, 
                   char **argv)
{
    int consistent;
    starreal minqualbefore;
    starreal meanqualbefore[NUMMEANTHRESHOLDS];
    starreal worstin;
    int i;
    
    /* check final mesh consistency */
    consistent = mytetcomplexconsistency(mesh);
    if (improvebehave.verbosity > 3)
    {
        printf("\nin the end mesh consistent = %d\n", consistent);
    }
    assert(consistent);
    
    if (IMPROVEPARANOID)
    {
        /* check that the final worst boundary dihedral matches start */
        printf("The worst boundary angle at the start: %g radians (%g degrees).\n", worstin, worstin * (180.0 / PI));
        worstin = worstinputangle(mesh);
        printf("The worst boundary angle at the end: %g radians (%g degrees).\n", worstin, worstin * (180.0 / PI));
    }
    
    if (improvebehave.verbosity > 3)
    {
        /* print out the properties of the worst tetrahedra */
        worsttetreport(mesh, improvebehave.qualmeasure, 5.0);
    }
    
    /* record final qualities */
    fillstackqual(mesh, tetstack, improvebehave.qualmeasure, HUGEFLOAT, meanqualbefore, &minqualbefore);
    for (i=0; i<NUMMEANTHRESHOLDS; i++)
    {
        stats.finishmeanquals[i] = meanqualbefore[i];
    }
    
    stats.finishnumverts = countverts(vertexpool);
    stats.finishnumtets = counttets(mesh);
    
    /* print final mesh improvement statistics */
    if (improvebehave.verbosity > 2)
    {
        printstats(mesh);
        checkquadrics(mesh);
    }
    
    if (improvebehave.verbosity > 1)
    {
        /* print mesh quality statistics after improvement has been done */
        printf("\nHere are quality statistics on the improved mesh:\n");
        improvestatistics(behave, mesh, false);
        
        if (improvebehave.anisotropic)
        {
            printf("Quality stats (ISOTROPIC SPACE):\n");
            improvestatistics(behave, mesh, true);
        }
    }
    
    /* print final mesh out. If we're animating we've already got it. */
    if (improvebehave.animate == false)
    {
        outputqualmesh(behave, in, vertexpool, mesh, argc, argv, 0, 0, 0, QUALMINSINE);
    }
    
    /* clean up array pools */
    stackdeinit(tetstack);
    arraypooldeinit(&vertexinfo);
    stackdeinit(journal);
}

/* top-level function to perform static mesh improvement */
void staticimprove(struct behavior *behave,
                   struct inputs *in,
                   struct proxipool *vertexpool,
                   struct tetcomplex *mesh,
                   int argc,
                   char **argv)
{
    struct arraypoolstack tetstack;         /* stack of tets to be improved */
    int passnum = 1;                        /* current improvement pass */
    int roundsnoimprovement = 0;            /* number of passes since mesh improved */
    bool meansuccess = false;               /* thresholded mean success */
    bool minsuccess = false;                /* minimum quality success */
    starreal bestmeans[NUMMEANTHRESHOLDS];  /* current best thresholded means */
    bool stop, stop1 = false;               /* whether to continue improvement */
    int numdesperate = 0;
    
#ifndef NO_TIMER
    /* timing vars */
    struct timeval tv0, tv2;
    struct timezone tz;
    /* get initial time */
    gettimeofday(&tv0, &tz);
    stats.starttime = tv0;
#endif /* not NO_TIMER */
    
    /* perform improvement initialization */
    improveinit(mesh, vertexpool, &tetstack, behave, in, argc, argv, bestmeans);
    
    if (improvebehave.verbosity > 1) sizereport(mesh);
    
    /********** INITIAL SMOOTHING AND TOPO PASSES **********/
    
    /* initial global smoothing pass */
    stop = pass(SMOOTHPASS, mesh, &tetstack, 
                HUGEFLOAT, &minsuccess, &meansuccess, passnum++, bestmeans, 
                behave, in, vertexpool, argc, argv);
    /* initial global topological improvement pass */
    stop = pass(TOPOPASS, mesh, &tetstack,
                HUGEFLOAT, &minsuccess, &meansuccess, passnum++, bestmeans,
                behave, in, vertexpool, argc, argv);
    /* initial global contraction improvement pass */
    if (improvebehave.anisotropic == false)
    {
        stop = pass(CONTRACTALLPASS, mesh, &tetstack,
                    HUGEFLOAT, &minsuccess, &meansuccess, passnum++, bestmeans,
                    behave, in, vertexpool, argc, argv);
    }
    
    /***************** SIZE CONTROL *************************/
    if (improvebehave.sizing)
    {
        passnum = sizecontrol(mesh, behave, in, vertexpool, argc, argv);
    }
    
    /*************** MAIN IMPROVEMENT LOOP ******************/
    while (roundsnoimprovement < STATICMAXPASSES)
    {
        /* if the mesh is already fine, stop improvement */
        if (stop) break;
        
        /* perform a smoothing pass */
        stop = pass(SMOOTHPASS, mesh, &tetstack, 
                    HUGEFLOAT, &minsuccess, &meansuccess, passnum++, bestmeans,
                    behave, in, vertexpool, argc, argv);
        if (stop) break;
        
        /* if the smoothing pass failed to sufficiently improve the mesh */
        if ((minsuccess == false) && (meansuccess == false))
        {
            /* perform a global topological pass */
            stop = pass(TOPOPASS, mesh, &tetstack,
                        HUGEFLOAT, &minsuccess, &meansuccess, passnum++, bestmeans, 
                        behave, in, vertexpool, argc, argv);
            if (stop) break;
            
            /* if the topo pass also failed */
            if ((minsuccess == false) && (meansuccess == false))
            {
                /* perform a contraction and insertion pass */
                if (improvebehave.enableinsert)
                {
                    /* potentially start with a pass of edge contraction */
                    if (improvebehave.edgecontraction)
                    {
                        stop1 = pass(CONTRACTPASS, mesh, &tetstack, 
                                    HUGEFLOAT, &minsuccess, &meansuccess, passnum++, bestmeans, 
                                    behave, in, vertexpool, argc, argv);
                    }
                    else
                    {
                        stop1 = false;
                    }
                    
                    if (roundsnoimprovement == 1 && numdesperate < DESPERATEMAXPASSES)
                    {
                        stop = pass(DESPERATEPASS, mesh, &tetstack, 
                                    HUGEFLOAT, &minsuccess, &meansuccess, passnum++, bestmeans, 
                                    behave, in, vertexpool, argc, argv);
                        numdesperate++;
                        if (improvebehave.verbosity > 2)
                        {
                            printf("Just completed desperate pass %d / %d\n", numdesperate, DESPERATEMAXPASSES);
                        }
                        if (stop || stop1) break;
                    }
                    else
                    {
                        stop = pass(INSERTPASS, mesh, &tetstack, 
                                    HUGEFLOAT, &minsuccess, &meansuccess, passnum++, bestmeans, 
                                    behave, in, vertexpool, argc, argv);
                        if (stop || stop1) break;
                    }
                }
            }
        }
        /* if this pass failed to see any improvement, note it */
        if ((minsuccess == false) && (meansuccess == false))
        {
            roundsnoimprovement++;
            if (improvebehave.verbosity > 2)
            {
                textcolor(BRIGHT, RED, BLACK);
                printf("Last %d passes there has been no improvement.\n", roundsnoimprovement);
                textcolor(RESET, WHITE, BLACK);
            }
        }
        /* reset number of rounds on smoothing success */
        else 
        {
            if (improvebehave.verbosity > 2)
            {
                textcolor(BRIGHT, GREEN, BLACK);
                printf("Resetting failed passes count on success.\n");
                textcolor(RESET, WHITE, BLACK);
            }
            roundsnoimprovement = 0;
        }
    }
    
    /******************** END MAIN IMPROVEMENT LOOP **********************/
    
#ifndef NO_TIMER
    /* record total time */
    gettimeofday(&tv2, &tz);
    stats.totalmsec = msecelapsed(tv0, tv2);
#endif /* not NO_TIMER */
    
    /* perform post-improvement cleanup */
    improvedeinit(mesh, vertexpool, &tetstack, behave, in, argc, argv);
}


<|start_filename|>vtkVmtk/Contrib/vtkvmtkConcaveAnnularCapPolyData.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkConcaveAnnularCapPolyData.cxx,v $
Language:  C++
Date:      $Date: 2012/09/19 $
Version:   $Revision: 1.0 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

  Note: this class was contributed by
    <NAME>
	Simula Research Laboratory
  Based on vtkvmtkAnnularCapPolyData by <NAME>.

=========================================================================*/

#include "vtkvmtkConcaveAnnularCapPolyData.h"
#include "vtkvmtkPolyDataBoundaryExtractor.h"
#include "vtkvmtkBoundaryReferenceSystems.h"
#include "vtkPolyData.h"
#include "vtkCellArray.h"
#include "vtkPointData.h"
#include "vtkCellData.h"
#include "vtkPolygon.h"
#include "vtkPolyLine.h"
#include "vtkIntArray.h"
#include "vtkMath.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkSmartPointer.h"
#include "vtkVersion.h"

#include <limits>


vtkStandardNewMacro(vtkvmtkConcaveAnnularCapPolyData);

namespace {
void info(const std::string & s)
{
  std::cout << s << std::endl;
}

void cross_diff(const double start[3], const double forward[3], const double center[3], double cross[3])
{
  double vectorToStart[3] = { start[0] - center[0],
                              start[1] - center[1],
                              start[2] - center[2] };
  double vectorToForward[3] = { forward[0] - center[0],
                                forward[1] - center[1],
                                forward[2] - center[2] };
  vtkMath::Cross(vectorToStart, vectorToForward, cross);
}
}

vtkvmtkConcaveAnnularCapPolyData::vtkvmtkConcaveAnnularCapPolyData()
{
  this->BoundaryIds = NULL;
  this->CellEntityIdsArrayName = NULL;
  this->CellEntityIdOffset = 1;
}

vtkvmtkConcaveAnnularCapPolyData::~vtkvmtkConcaveAnnularCapPolyData()
{
  if (this->CellEntityIdsArrayName)
    {
    delete[] this->CellEntityIdsArrayName;
    this->CellEntityIdsArrayName = NULL;
    }
  if (this->BoundaryIds)
    {
    this->BoundaryIds->Delete();
    this->BoundaryIds = NULL;
    }
}

#include <vector>
#include <utility>
using std::vector;
using std::pair;
using std::make_pair;
typedef pair<vtkIdType,vtkIdType> IdPair;

vector<IdPair> build_closest_pairs(vtkSmartPointer<vtkPoints> barycenters, vtkIdList* boundaryIds)
{
  int numberOfBoundaries = barycenters->GetNumberOfPoints();

  vector<IdPair> pairs;

  // Allocate array for marking visited boundaries
  vector<bool> visited(numberOfBoundaries);
  if (boundaryIds)
    {
      // Skip ids not in boundaryIds list
      for (int i=0; i<numberOfBoundaries; i++)
        {
          visited[i] = true;
        }
      for (int i=0; i<boundaryIds->GetNumberOfIds(); i++)
      {
        visited[boundaryIds->GetId(i)] = false;
      }
    }
  else
    {
    // Skip nothing
    for (int i=0; i<numberOfBoundaries; i++)
      {
        visited[i] = false;
      }
    }

  // Find the closest pairs of boundaries by comparing barycenter distances
  for (int i=0; i<numberOfBoundaries; i++)
    {
    if (visited[i])
      {
        continue;
      }
    double barycenter[3];
    barycenters->GetPoint(i, barycenter);

    // Find which boundary j is closest to boundary i
    double minBarycenterDistance2 = std::numeric_limits<double>::max();
    vtkIdType closest = -1;
    for (int j=i+1; j<numberOfBoundaries; j++)
      {
      if (visited[j])
        {
        continue;
        }

      // Fetch barycenter j
      double currentBarycenter[3];
      barycenters->GetPoint(j, currentBarycenter);

      // Pick boundary j if the distance to boundary i is the smallest so far
      double distance2 = vtkMath::Distance2BetweenPoints(barycenter,currentBarycenter);
      if (distance2 < minBarycenterDistance2)
        {
        minBarycenterDistance2 = distance2;
        closest = j;
        }
      }

    // Mark as visited and add pair
    //std::cout << "i, closest = " << i << ", " << closest << std::endl;
    visited[i] = true;
    visited[closest] = true;
    pairs.push_back(make_pair(i, closest));
    }
  return pairs;
}

IdPair find_closest_points(vtkPolyData * points, vtkSmartPointer<vtkIdList> pointIds0, vtkSmartPointer<vtkIdList> pointIds1)
{
  vtkIdType i0 = -1;
  vtkIdType i1 = -1;
  double minPointDistance2 = std::numeric_limits<double>::max();
  int n0 = pointIds0->GetNumberOfIds();
  int n1 = pointIds1->GetNumberOfIds();
  for (int j0=0; j0<n0; j0++)
    {
    double point0[3];
    points->GetPoint(pointIds0->GetId(j0), point0);
    for (int j1=0; j1<n1; j1++)
      {
      double point1[3];
      points->GetPoint(pointIds1->GetId(j1), point1);
      double distance2 = vtkMath::Distance2BetweenPoints(point0, point1);
      if (distance2 < minPointDistance2)
        {
        i0 = j0;
        i1 = j1;
        minPointDistance2 = distance2;
        }
      }
    }
  return make_pair(i0, i1);
}

int vtkvmtkConcaveAnnularCapPolyData::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // Administrative data type wrestling
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  // Minimal check that we get at least some data
  if ( input->GetNumberOfPoints() < 6 )
    {
    vtkErrorMacro(<< "Error: too few input points.");
    return 1;
    }
  input->BuildLinks();

  // Allocate output objects
  vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
  newPoints->DeepCopy(input->GetPoints());
  vtkSmartPointer<vtkCellArray> newPolys = vtkSmartPointer<vtkCellArray>::New();
  newPolys->DeepCopy(input->GetPolys());

  // Mark cells if we have a nonempty name
  bool markCells = this->CellEntityIdsArrayName && this->CellEntityIdsArrayName[0];
  vtkSmartPointer<vtkIntArray> cellEntityIdsArray;
  if (markCells)
    {
    cellEntityIdsArray = vtkSmartPointer<vtkIntArray>::New();
    cellEntityIdsArray->SetName(this->CellEntityIdsArrayName);
    if (input->GetCellData()->GetArray(this->CellEntityIdsArrayName))
      {
      cellEntityIdsArray->DeepCopy(input->GetCellData()->GetArray(this->CellEntityIdsArrayName));
      }
    else
      {
      cellEntityIdsArray->SetNumberOfTuples(newPolys->GetNumberOfCells());
      cellEntityIdsArray->FillComponent(0,static_cast<double>(this->CellEntityIdOffset));
      }
    }

  // Extract all boundaries (polylines) from input mesh
  info("Finding boundaries of input surface...");
  vtkSmartPointer<vtkvmtkPolyDataBoundaryExtractor> boundaryExtractor =
      vtkSmartPointer<vtkvmtkPolyDataBoundaryExtractor>::New();
#if (VTK_MAJOR_VERSION <= 5)
  boundaryExtractor->SetInput(input);
#else
  boundaryExtractor->SetInputData(input);
#endif
  boundaryExtractor->Update();
  vtkPolyData* boundaries = boundaryExtractor->GetOutput();

  int numberOfBoundaries = boundaries->GetNumberOfCells();
  std::cout << "Found " << numberOfBoundaries << " boundaries." << std::endl;

  // Compute barycenters for all boundaries
  info("Computing boundary barycenters...");
  vtkSmartPointer<vtkPoints> barycenters = vtkSmartPointer<vtkPoints>::New();
  barycenters->SetNumberOfPoints(numberOfBoundaries);
  for (int i=0; i<numberOfBoundaries; i++)
    {
    double barycenter[3];
    vtkvmtkBoundaryReferenceSystems::ComputeBoundaryBarycenter(boundaries->GetCell(i)->GetPoints(), barycenter);
    barycenters->SetPoint(i, barycenter);
    }

  // Build pairs of boundaries from closest barycenter pairs, limited to list of input ids if any
  info("Pairing boundaries...");
  if ( (this->BoundaryIds && this->BoundaryIds->GetNumberOfIds() % 2)
       || (!this->BoundaryIds && numberOfBoundaries % 2) )
    {
    vtkErrorMacro(<< "Error: the number of boundaries must be even.");
    }
  vector<IdPair> boundaryPairs = build_closest_pairs(barycenters, this->BoundaryIds);

  // Loop over all boundary pairings uniquely
  for (size_t pairingCount=0; pairingCount<boundaryPairs.size(); ++pairingCount)
    {
    vtkIdType i0 = boundaryPairs[pairingCount].first;
    vtkIdType i1 = boundaryPairs[pairingCount].second;

    // These are point ids for all boundaries globally, pointing into global vertex array
    info("Finding boundary point ids...");
    vtkIdTypeArray * boundaryPointIdsArray = vtkIdTypeArray::SafeDownCast(boundaries->GetPointData()->GetScalars());

    // Collect (global!) point ids for boundary 0 in current pairing into a contiguous array
    vtkPolyLine* boundary0 = vtkPolyLine::SafeDownCast(boundaries->GetCell(i0));
    vtkIdType numberOfBoundaryPoints0 = boundary0->GetNumberOfPoints();
    if (numberOfBoundaryPoints0 < 8)
      {
      vtkErrorMacro(<< "Error: Assuming at least 8 boundary points!");
      }
    vtkSmartPointer<vtkIdList> boundaryPointIds0 = vtkSmartPointer<vtkIdList>::New();
    boundaryPointIds0->SetNumberOfIds(numberOfBoundaryPoints0);
    for (int j=0; j<numberOfBoundaryPoints0; j++)
      {
      // Translation: local0[j] = global[local2global0[j]];
      boundaryPointIds0->SetId(j, boundaryPointIdsArray->GetValue(boundary0->GetPointId(j)));
      }

    // Collect (global!) point ids for boundary 1 in current pairing into a contiguous array
    vtkPolyLine* boundary1 = vtkPolyLine::SafeDownCast(boundaries->GetCell(i1));
    vtkIdType numberOfBoundaryPoints1 = boundary1->GetNumberOfPoints();
    if (numberOfBoundaryPoints1 < 8)
      {
      vtkErrorMacro(<< "Error: Assuming at least 8 boundary points!");
      }
    vtkSmartPointer<vtkIdList> boundaryPointIds1 = vtkSmartPointer<vtkIdList>::New();
    boundaryPointIds1->SetNumberOfIds(numberOfBoundaryPoints1);
    for (int j=0; j<numberOfBoundaryPoints1; j++)
      {
      // Translation: local1[j] = global[local2global1[j]];
      boundaryPointIds1->SetId(j, boundaryPointIdsArray->GetValue(boundary1->GetPointId(j)));
      }

    // Find the two closest vertices between the boundaries
    info("Finding closest vertices...");
    IdPair starts = find_closest_points(input, boundaryPointIds0, boundaryPointIds1);
    vtkIdType i0start = starts.first;
    vtkIdType i1start = starts.second;

    // Compute direction of paired boundaries
    // TODO: Why was this numBP0/8 in annular case? Numerical robustness or something?
    int i0forward = (i0start + 1) % numberOfBoundaryPoints0;
    int i1forward = (i1start + 1) % numberOfBoundaryPoints1;
    double cross[2][3];
    double barycenter[3];
    double startingPoint[3];
    double pointForward[3];

    barycenters->GetPoint(i0, barycenter);
    input->GetPoint(boundaryPointIds0->GetId(i0start), startingPoint);
    input->GetPoint(boundaryPointIds0->GetId(i0forward), pointForward);
    cross_diff(startingPoint, pointForward, barycenter, cross[0]);

    barycenters->GetPoint(i1, barycenter);
    input->GetPoint(boundaryPointIds1->GetId(i1start), startingPoint);
    input->GetPoint(boundaryPointIds1->GetId(i1forward), pointForward);
    cross_diff(startingPoint, pointForward, barycenter, cross[1]);

    int dir0 = +1; // TODO: Does the absolute direction matter?
    bool backwards = vtkMath::Dot(cross[0], cross[1]) < 0.0;
    int dir1 = backwards ? dir0: -dir0;

    // Compute vectors in directions away from endpoints of polygon
    double nudgeFactor = 0.01;
    i0forward = (i0start + dir0 + numberOfBoundaryPoints0) % numberOfBoundaryPoints0;
    input->GetPoint(boundaryPointIds0->GetId(i0start), startingPoint);
    input->GetPoint(boundaryPointIds0->GetId(i0forward), pointForward);
    double nudgeVector0[3] = { nudgeFactor*(pointForward[0] - startingPoint[0]),
                               nudgeFactor*(pointForward[1] - startingPoint[1]),
                               nudgeFactor*(pointForward[2] - startingPoint[2]) };
    i1forward = (i1start - dir1 + numberOfBoundaryPoints1) % numberOfBoundaryPoints1;
    input->GetPoint(boundaryPointIds1->GetId(i1start), startingPoint);
    input->GetPoint(boundaryPointIds1->GetId(i1forward), pointForward);
    double nudgeVector1[3] = { nudgeFactor*(pointForward[0] - startingPoint[0]),
                               nudgeFactor*(pointForward[1] - startingPoint[1]),
                               nudgeFactor*(pointForward[2] - startingPoint[2]) };

    // Use vtkPolygon::Triangulate to mesh between boundary pair
    info("Setting up n-sided polygon...");
    // Initialize a vtkPolygon instance with list of boundary points
    int npts = numberOfBoundaryPoints0 + numberOfBoundaryPoints1 + 2;
    vtkSmartPointer<vtkPolygon> polygon = vtkSmartPointer<vtkPolygon>::New();
    vtkPoints * polygonPoints = polygon->GetPoints();
    vtkIdList * polygonPointIds = polygon->GetPointIds();
    polygonPoints->SetNumberOfPoints(npts);
    polygonPointIds->SetNumberOfIds(npts);
    vector<vtkIdType> polygonPointIdToGlobalPointId(npts);
    // Add all vertices from the inner polygon in one
    // direction, starting and ending with i0start.
    int kk = 0;
    for (int k=0; k<=numberOfBoundaryPoints0; k++) // NB! Using <= to repeat first point.
      {
      vtkIdType bp0id = (i0start + dir0*k + numberOfBoundaryPoints0) % numberOfBoundaryPoints0;
      vtkIdType pid = boundaryPointIds0->GetId(bp0id);
      double point[3];
      input->GetPoint(pid, point);
      if (k == 0)
        {
        point[0] += nudgeVector0[0];
        point[1] += nudgeVector0[1];
        point[2] += nudgeVector0[2];
        }
      polygonPointIdToGlobalPointId[kk] = pid;
      polygonPointIds->SetId(kk,kk);
      polygonPoints->InsertPoint(kk, point);
      kk++;
      }
    // Continue by adding all vertices from the outer polygon in the
    // opposite direction, starting and ending with i1start.
    for (int k=0; k<=numberOfBoundaryPoints1; k++) // NB! Using <= to repeat first point.
      {
      vtkIdType bp1id = (i1start + dir1*k + numberOfBoundaryPoints1) % numberOfBoundaryPoints1;
      vtkIdType pid = boundaryPointIds1->GetId(bp1id);
      double point[3];
      input->GetPoint(pid, point);
      if (k == numberOfBoundaryPoints1)
        {
        point[0] += nudgeVector1[0];
        point[1] += nudgeVector1[1];
        point[2] += nudgeVector1[2];
        }
      polygonPointIdToGlobalPointId[kk] = pid;
      polygonPointIds->SetId(kk,kk);
      polygonPoints->InsertPoint(kk, point);
      kk++;
      }

    // Call polygon->Triangulate(...) to mesh the interior of the concave polygon
    info("Triangulating...");
    vtkSmartPointer<vtkIdList> outTris = vtkSmartPointer<vtkIdList>::New();
    int triRes = polygon->NonDegenerateTriangulate(outTris);
    if (triRes == 0)
      {
      vtkErrorMacro(<< "Error: Numerical degeneracy when triangulating endcaps surface! Code: " << triRes);
      }

    // Output of triangulation is now in outTris, outPoints, append to newPolys
    info("Appending datasets...");
    size_t nt = outTris->GetNumberOfIds()/3;
    for (size_t it=0; it<nt; ++it)
      {
      // Get mapped point ids for new triangle
      vtkIdType triangleIds[3] = { polygonPointIdToGlobalPointId[outTris->GetId(3*it+0)],
                                   polygonPointIdToGlobalPointId[outTris->GetId(3*it+1)],
                                   polygonPointIdToGlobalPointId[outTris->GetId(3*it+2)] };

      // Insert new triangle in endcaps mesh!
      newPolys->InsertNextCell(3, triangleIds);
      // Mark this new triangle with the pairing number (starting from 1) + given offset
      if (markCells)
        {
        cellEntityIdsArray->InsertNextValue(pairingCount + 1 + this->CellEntityIdOffset);
        }
      }
    } // end for loop over boundary pairs

  // Collect output datastructures
  output->SetPoints(newPoints);
  output->SetPolys(newPolys);
  output->GetPointData()->PassData(input->GetPointData());
  if (markCells)
    {
    output->GetCellData()->AddArray(cellEntityIdsArray);
    }
  info("Done!");

  return 1;
}

void vtkvmtkConcaveAnnularCapPolyData::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


<|start_filename|>vtkVmtk/Contrib/vtkvmtkCenterlineInterpolateArray.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkCenterlineInterpolateArray.cxx,v $
  Language:  C++
  Date:      $$
  Version:   $$

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

  Note: this class was contributed by 
	<NAME>
	Kalkulo AS
	Simula Research Laboratory
=========================================================================*/

#include "vtkvmtkCenterlineInterpolateArray.h"

#include <algorithm>
#include <vector>

#include "vtkPointData.h"
#include "vtkPolyLine.h"
#include "vtkMath.h"
#include "vtkBitArray.h"
#include "vtkDoubleArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkIOStream.h"
#include "vtkVersion.h"

#include "vtkvmtkConstants.h"
#include "vtkvmtkCenterlineAttributesFilter.h"


vtkStandardNewMacro(vtkvmtkCenterlineInterpolateArray);

vtkvmtkCenterlineInterpolateArray::vtkvmtkCenterlineInterpolateArray() 
{
  this->InterpolatedArrayName = NULL;

  this->DefaultValue = 0;
  this->Values = NULL;
  this->ValuesIds = NULL;
}

vtkvmtkCenterlineInterpolateArray::~vtkvmtkCenterlineInterpolateArray()
{
  if (this->InterpolatedArrayName)
    {
    delete[] this->InterpolatedArrayName;
    this->InterpolatedArrayName = NULL;
    }
    
  if (this->Values)
    {
    this->Values->Delete();
    this->Values = NULL;
    }
    
  if (this->ValuesIds)
    {
    this->ValuesIds->Delete();
    this->ValuesIds = NULL;
    }
}

int vtkvmtkCenterlineInterpolateArray::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (!this->InterpolatedArrayName)
    {
    vtkErrorMacro(<<"InterpolatedArrayName not set.");
    return 1;
    }

  if (!this->Values)
    {
    vtkErrorMacro(<<"Values not set");
    return 1;
    }
    
  if (!this->ValuesIds)
    {
    vtkErrorMacro(<<"ValuesIds not set");
    return 1;
    }
    
  if (this->Values->GetNumberOfTuples() != this->ValuesIds->GetNumberOfIds())
    {
    vtkErrorMacro(<<"Inconsistent number of values/ids");
    return 1;
    }

  int numberOfInputPoints = input->GetNumberOfPoints();

  output->DeepCopy(input);

  
  vtkDataArray* interpolatedArray =  output->GetPointData()->GetArray(this->InterpolatedArrayName);
  
  bool createArray = !interpolatedArray;
  
  if (createArray) 
    {
    interpolatedArray = vtkDoubleArray::New();
    interpolatedArray->SetName(this->InterpolatedArrayName);
    interpolatedArray->SetNumberOfComponents(this->Values->GetNumberOfComponents());
    interpolatedArray->SetNumberOfTuples(numberOfInputPoints);
    for (int i=0; i<interpolatedArray->GetNumberOfComponents(); i++)
      {
      interpolatedArray->FillComponent(i, this->DefaultValue);
      }
    output->GetPointData()->AddArray(interpolatedArray);
    }
    
  int numberOfComponents = std::min(interpolatedArray->GetNumberOfComponents(),this->Values->GetNumberOfComponents());
    
  //Compute abscissas for the centerlines
  vtkvmtkCenterlineAttributesFilter *attribFilter = vtkvmtkCenterlineAttributesFilter::New();
#if (VTK_MAJOR_VERSION <= 5)
  attribFilter->SetInput(input);
#else
  attribFilter->SetInputData(input);
#endif
  attribFilter->SetAbscissasArrayName("Abscissa");
  attribFilter->SetParallelTransportNormalsArrayName("ParallelTransportNormals");
  attribFilter->Update();
  vtkDataArray *abscissaArray = attribFilter->GetOutput()->GetPointData()->GetArray("Abscissa");
  
  //Indicates which point have values
  vtkBitArray *hasValueArray = vtkBitArray::New();
  hasValueArray->SetNumberOfComponents(1);
  hasValueArray->SetNumberOfTuples(numberOfInputPoints);
  hasValueArray->FillComponent(0,false);
  
  for (int i=0; i<this->ValuesIds->GetNumberOfIds(); i++)
    {
    hasValueArray->SetValue(this->ValuesIds->GetId(i),true);
    for (int j=0; j<numberOfComponents; j++)
      {
      interpolatedArray->SetComponent(this->ValuesIds->GetId(i),j,this->Values->GetComponent(i,j));
      }
    }
  
  int numberOfInputCells = input->GetNumberOfCells();
 
  
  for (int i=0; i<numberOfInputCells; i++)
    {
    vtkPolyLine* polyLine = vtkPolyLine::SafeDownCast(input->GetCell(i));
    if (!polyLine)
      {
      continue;
      }
      
    int numberOfLinePoints = polyLine->GetNumberOfPoints();
      
    bool foundValue = false;
    int startInd = 0;
    //Find the first point having a value
    while ((startInd<numberOfLinePoints) && (!foundValue)) 
      {
      foundValue = hasValueArray->GetValue(polyLine->GetPointId(startInd++));
      }
      
    //If no point with a value has been found skip to next line
    if ((startInd==numberOfLinePoints) && (!foundValue))
      {
      continue;
      }
      
    //Otherwise we have our first value fill the previous points with this value
    startInd--;
    std::vector<double> startVal(numberOfComponents);
    for (int j=0; j<numberOfComponents; j++)
      {
      startVal[j] = interpolatedArray->GetComponent(polyLine->GetPointId(startInd),j);
      }
    double startAbs = abscissaArray->GetComponent(polyLine->GetPointId(startInd),0);
    
    for (int j=0; j<startInd; j++)
      {
      for (int k=0; k<numberOfComponents; k++)
        {
        interpolatedArray->SetComponent(polyLine->GetPointId(j),k,startVal[k]);
        }
      hasValueArray->SetValue(polyLine->GetPointId(j),true);
      }
    
    int endInd = startInd + 1;
    foundValue = false;
    while (endInd<numberOfLinePoints)
      {
      foundValue = hasValueArray->GetValue(polyLine->GetPointId(endInd));
      if (foundValue)
        {
        //Interpolate between the start and end values
        std::vector<double> endVal(numberOfComponents);
        for (int j=0; j<numberOfComponents; j++)
          {
          endVal[j] = interpolatedArray->GetComponent(polyLine->GetPointId(endInd),j);
          }
        double endAbs = abscissaArray->GetComponent(polyLine->GetPointId(endInd),0);
        double absDiff = endAbs - startAbs;
        if (absDiff!=0.) 
          {
          float invAbsDiff = 1./absDiff;
          for (int j=startInd+1;j<endInd;j++)
            {
              double currAbs = abscissaArray->GetComponent(polyLine->GetPointId(j),0);
              for (int k=0; k<numberOfComponents; k++)
                {
                double newVal = startVal[k] + (currAbs - startAbs)*invAbsDiff*(endVal[k] - startVal[k]);
                interpolatedArray->SetComponent(polyLine->GetPointId(j),k,newVal);
                }
              hasValueArray->SetValue(polyLine->GetPointId(j),true);
            }
          }
          //Replace the end value by the start value
          startInd = endInd;
          startVal = endVal;
          startAbs = endAbs;
        }
      endInd++;
      }
      
    //Fill the remaining values
    for (int j=startInd+1; j<numberOfLinePoints; j++)
      {
      for (int k=0; k<numberOfComponents; k++)
        {
        interpolatedArray->SetComponent(polyLine->GetPointId(j),k,startVal[k]);
        }
      hasValueArray->SetValue(polyLine->GetPointId(j),true);
      }
    }

  if (createArray) interpolatedArray->Delete();
  attribFilter->Delete();
  hasValueArray->Delete();

  return 1;
}


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/topological.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*  topological improvement functions                                        */
/*                                                                           */
/*****************************************************************************/

/* determine the number of reflex edges that a face has, to determine what sort
   of flips might be done to it */
int countreflex(struct tetcomplex *mesh,
                tag vtx1,
                tag vtx2,
                tag vtx3,
                int *numcoplanar,
                int coplanaredges[][2])
{
    tag adjacencies[2];      /* the tags for the top and bottom vertices */
    starreal *facepoints[3]; /* the vertices of the face */
    starreal *apexpoints[2]; /* the two apex points from the adjacency query */
    int foundtriangle;       /* was the queried face even in the mesh? */
    int reflexcount = 0;     /* the number of reflex edges detected */
    int i;                   /* loop counter */
    starreal orientation;      /* orientation of edges */
    /* tag toptet[4]; */     /* "top" tet (RHR around face points to its apex) */
    /* tag bottet[4]; */     /* "bottom" tet */
    *numcoplanar = 0;
    
    /* find the two tets that share this face */
    foundtriangle = tetcomplexadjacencies(mesh, vtx1, vtx2, vtx3, adjacencies);
    
    if (foundtriangle != 1)
    {
        printf("failed to find face %d %d %d in countreflex.\n", (int) vtx1, (int) vtx2, (int) vtx3);
    }
    
    /* make sure this triangle actually exists in the mesh */
    assert(foundtriangle == 1);
    
    /* check to see if one of the tets is a ghost tet */
    if (adjacencies[0] == GHOSTVERTEX || adjacencies[1] == GHOSTVERTEX)
    {
        return -1; /* don't try to handle this case yet */
    }
    
    /* get the vertices of the face and the apices */
    facepoints[0] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx1))->coord;
    facepoints[1] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx2))->coord;
    facepoints[2] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx3))->coord;
    
    apexpoints[0] = ((struct vertex *) tetcomplextag2vertex(mesh, adjacencies[0]))->coord;
    apexpoints[1] = ((struct vertex *) tetcomplextag2vertex(mesh, adjacencies[1]))->coord;
    
    /* check whether each edge is a reflex edge. 
       the edge between the two apex vertices goes from 
       adjacencies[0] to adjacences[1]. We can determine if
       an edge is a reflex edge by using an orientation test:
       
       orient3d(p1,p2,adjacencies[0],adjacencies[1])
       
       will return + if the edge from p1 to p2 is convex
       will return - if the edge from p1 to p2 is reflex
       will return 0 if the edge from p1 to p2 intersects the top-bottom edge
       
       we need to run this test for each edge of the face
    */
    for (i=0; i<3; i++)
    {
        orientation = orient3d(&behave,
                               facepoints[i],
                               facepoints[(i+1) % 3],
                               apexpoints[0],
                               apexpoints[1]);
        if (orientation < 0)
        {
            /* found a reflex edge */
            reflexcount++;
        }
        else
        {
            if (orientation == 0)
            {
                /* this edge divides two coplanar faces */
                coplanaredges[*numcoplanar][0] = i;
                coplanaredges[*numcoplanar][1] = (i+1) % 3;
                (*numcoplanar)++;
                
                if (improvebehave.verbosity > 5)
                {
                    printf("found coplanar faces! marking\n");
                }
            }
        }
    }
    
    /* a tet can have at most 2 reflex edges / edges connecting coplanar faces */
    assert(reflexcount + *numcoplanar < 3);
    
    /* debugging printout to visually verify reflex edge count */
    /*
    if (reflexcount > 1)
    {
        printf("\nI think I found a face with %d reflex edges. The two tets involved are:\n", reflexcount);
        toptet[0] = adjacencies[0];
        toptet[1] = face[0];
        toptet[2] = face[1];
        toptet[3] = face[2];
        
        bottet[0] = adjacencies[1];
        bottet[1] = face[2];
        bottet[2] = face[1];
        bottet[3] = face[0];
        
        printf("two tets involved are:\n{");
        printtetverts(mesh, toptet);
        printf(",\n");
        printtetverts(mesh, bottet);
        printf("}\n");
    }
    */
    
    return reflexcount;
}

/* my wrapper for single tet insertion, gets recorded in the journal */
void inserttet(struct tetcomplex *mesh,
               tag vtx1,
               tag vtx2,
               tag vtx3,
               tag vtx4,
               bool record)
{
    int r;
    tag verts[4];
    
    verts[0] = vtx1;
    verts[1] = vtx2;
    verts[2] = vtx3;
    verts[3] = vtx4;
    
    r = tetcomplexinserttet(mesh, vtx1, vtx2, vtx3, vtx4);
    assert(r);
    
    /* if asked, record this deletion in the journal */
    if (record)
    {
        insertjournalentry(mesh, INSERTTET, verts, 4, (starreal *) NULL, (starreal *) NULL);
    }
}

/* my wrapper for single tet deletion, gets recorded in the journal */
void deletetet(struct tetcomplex *mesh,
               tag vtx1,
               tag vtx2,
               tag vtx3,
               tag vtx4,
               bool record)
{
    int r;
    tag verts[4];
    
    verts[0] = vtx1;
    verts[1] = vtx2;
    verts[2] = vtx3;
    verts[3] = vtx4;
    
    /* check that tet existst */
    assert(tetexists(mesh, vtx1, vtx2, vtx3, vtx4));
    
    r = tetcomplexdeletetet(mesh, vtx1, vtx2, vtx3, vtx4);
    assert(r);
    
    /* if asked, record this deletion in the journal */
    if (record)
    {
        insertjournalentry(mesh, DELETETET, verts, 4, (starreal *) NULL, (starreal *) NULL);
    }
}

/* bryan's own version of 2-3 flip that uses explicit
   delete and insert calls to perform the flip */
void flip23(struct tetcomplex *mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtxbot,
            tag vtxtop,
            bool record)
{
    int r;
    tag verts[5];
    
    verts[0] = vtx1;
    verts[1] = vtx2;
    verts[2] = vtx3;
    verts[3] = vtxbot;
    verts[4] = vtxtop;
    
    if (improvebehave.jflips)
    {
        /* use Jonathan's faster flip routine */
        tetcomplex23flip(mesh, vtxtop, vtx1, vtx2, vtx3, vtxbot);
    }
    else
    {
        /* delete the tet (top, 1, 2, 3) */
        assert(tetexists(mesh, vtxtop, vtx1, vtx2, vtx3));
        r = tetcomplexdeletetet(mesh, vtxtop, vtx1, vtx2, vtx3);
        assert(r);
    
        /* delete the tet (bot, 3, 2, 1) */
        assert(tetexists(mesh, vtxbot, vtx3, vtx2, vtx1));
        r = tetcomplexdeletetet(mesh, vtxbot, vtx3, vtx2, vtx1);
        assert(r);
    
        /* add the tet (top, 1, 2, bot) */
        r = tetcomplexinserttet(mesh, vtxtop, vtx1, vtx2, vtxbot);
        assert(r);
    
        /* add the tet (top, 2, 3, bot) */
        r = tetcomplexinserttet(mesh, vtxtop, vtx2, vtx3, vtxbot);
        assert(r);
    
        /* add the tet (top, 3, 1, bot) */
        r = tetcomplexinserttet(mesh, vtxtop, vtx3, vtx1, vtxbot);
        assert(r);
    }
    
    /* if asked, record this flip in the journal */
    if (record)
    {
        insertjournalentry(mesh, FLIP23, verts, 5, (starreal *) NULL, (starreal *) NULL);
    }
}

/* bryan's own version of a 3-2 flip that uses explicit
   delete and insert calls to perform the flip */
void flip32(struct tetcomplex *mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtxbot,
            tag vtxtop,
            bool record)
{
    int r;
    tag verts[5];
    
    verts[0] = vtx1;
    verts[1] = vtx2;
    verts[2] = vtx3;
    verts[3] = vtxbot;
    verts[4] = vtxtop;
    
    if (improvebehave.jflips)
    {
        /* use Jonathan's fast flip */
        tetcomplex32flip(mesh, vtxtop, vtx1, vtx2, vtx3, vtxbot);
    }
    else
    {
        /* delete the tet (top, 1, 2, bot) */
        assert(tetexists(mesh, vtxtop, vtx1, vtx2, vtxbot));
        r = tetcomplexdeletetet(mesh, vtxtop, vtx1, vtx2, vtxbot);
        assert(r);
    
        /* delete the tet (top, 2, 3, bot) */
        assert(tetexists(mesh, vtxtop, vtx2, vtx3, vtxbot));
        r = tetcomplexdeletetet(mesh, vtxtop, vtx2, vtx3, vtxbot);
        assert(r);
    
        /* delete the tet (top, 3, 1, bot) */
        r = tetcomplexdeletetet(mesh, vtxtop, vtx3, vtx1, vtxbot);
        assert(r);

        /* add the tet (top, 1, 2, 3) */
        r = tetcomplexinserttet(mesh, vtxtop, vtx1, vtx2, vtx3);
        assert(r);
    
        /* add the tet (bot, 3, 2, 1) */
        r = tetcomplexinserttet(mesh, vtxbot, vtx3, vtx2, vtx1);
        assert(r);
    }
    /* if asked, record this flip in the journal */
    if (record)
    {
        insertjournalentry(mesh, FLIP32, verts, 5, (starreal *) NULL, (starreal *) NULL);
    }
}

/* perform a 2-2 flip using the edge from vtx1 to vtx2 */
void flip22(struct tetcomplex *mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtxbot,
            tag vtxtop,
            bool record)
{
    int r;
    tag verts[5];
    
    verts[0] = vtx1;
    verts[1] = vtx2;
    verts[2] = vtx3;
    verts[3] = vtxbot;
    verts[4] = vtxtop;
    
    /* delete (top, 1, 2, 3) */
    r = tetcomplexdeletetet(mesh, vtxtop, vtx1, vtx2, vtx3);
    assert(r);
    
    /* delete (bot, 3, 2, 1) */
    r = tetcomplexdeletetet(mesh, vtxbot, vtx3, vtx2, vtx1);
    assert(r);
    
    /* insert (3, 1, top, bot) */
    r = tetcomplexinserttet(mesh, vtx3, vtx1, vtxtop, vtxbot);
    assert(r);
    
    /* insert (3, 2, bot, top) */
    r = tetcomplexinserttet(mesh, vtx3, vtx2, vtxbot, vtxtop);
    assert(r);
    
    if (record)
    {
        insertjournalentry(mesh, FLIP22, verts, 5, (starreal *) NULL, (starreal *) NULL);
    }
}

/* given the tet (1,2,3,4), and the vertex bodyvertex
   in its interior, delete the original tet and connect
   the interior vertex to the old vertices, forming 4 new
   tets */
void flip14(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag bodyvtx,
            bool record)
{
    int r;
    tag verts[5];
    
    verts[0] = vtx1;
    verts[1] = vtx2;
    verts[2] = vtx3;
    verts[3] = vtx4;
    verts[4] = bodyvtx;
    
    if (improvebehave.jflips)
    {
        /* use Jonathan's fast flip */
        tetcomplex14flip(mesh, vtx1, vtx2, vtx3, vtx4, bodyvtx);
    }
    else
    {
        /* delete the original tet */
        r = tetcomplexdeletetet(mesh, vtx1, vtx2, vtx3, vtx4);
        assert(r);
    
        /* insert the tet (1, 2, 3, b) */
        r = tetcomplexinserttet(mesh, vtx1, vtx2, vtx3, bodyvtx);
        assert(r);
    
        /* insert the tet (1, 3, 4, b) */
        r = tetcomplexinserttet(mesh, vtx1, vtx3, vtx4, bodyvtx);
        assert(r);
    
        /* insert the tet (1, 4, 2, b) */
        r = tetcomplexinserttet(mesh, vtx1, vtx4, vtx2, bodyvtx);
        assert(r);
    
        /* insert the tet (b, 2, 3, 4) */
        r = tetcomplexinserttet(mesh, bodyvtx, vtx2, vtx3, vtx4);
        assert(r);
    }
    
    /* if asked, record this flip in the journal */
    if (record)
    {
        insertjournalentry(mesh, FLIP14, verts, 5, (starreal *) NULL, (starreal *) NULL);
    }
}

/* reverses a 1-4 flip */
void flip41(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag bodyvtx,
            bool record)
{
    int r;
    tag verts[5];
    
    verts[0] = vtx1;
    verts[1] = vtx2;
    verts[2] = vtx3;
    verts[3] = vtx4;
    verts[4] = bodyvtx;
    
    if (improvebehave.jflips)
    {
        /* use Jonathan's fast flip */
        tetcomplex41flip(mesh, vtx1, vtx2, vtx3, vtx4, bodyvtx);
    }
    else
    {
        /* delete the tet (1, 2, 3, b) */
        r = tetcomplexdeletetet(mesh, vtx1, vtx2, vtx3, bodyvtx);
        assert(r);
        
        /* delete the tet (1, 3, 4, b) */
        r = tetcomplexdeletetet(mesh, vtx1, vtx3, vtx4, bodyvtx);
        assert(r);
        
        /* delete the tet (1, 4, 2, b) */
        r = tetcomplexdeletetet(mesh, vtx1, vtx4, vtx2, bodyvtx);
        assert(r);
        
        /* delete the tet (b, 2, 3, 4) */
        r = tetcomplexdeletetet(mesh, bodyvtx, vtx2, vtx3, vtx4);
        assert(r);
        
        /* insert the tet (1, 2, 3, 4) */
        r = tetcomplexinserttet(mesh, vtx1, vtx2, vtx3, vtx4);
        assert(r);
    }
    
    /* if asked, record this flip in the journal */
    if (record)
    {
        insertjournalentry(mesh, FLIP14, verts, 5, (starreal *) NULL, (starreal *) NULL);
    }
}

/* given a tetrahedron with a boundary face and a new vertex that
   lies inside that face, remove the old tet and create three new
   ones. vtx2, vtx3, vtx4 should be the boundary face oriented
   toward vtx1 with a right-hand rule */
void flip13(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag facetvtx,
            bool record)
{
    int r;
    tag verts[5];
    
    verts[0] = vtx1;
    verts[1] = vtx2;
    verts[2] = vtx3;
    verts[3] = vtx4;
    verts[4] = facetvtx;
    
    /* delete the original tet */
    r = tetcomplexdeletetet(mesh, vtx1, vtx2, vtx3, vtx4);
    assert(r);
    
    /* insert the tet (1, 2, f, 4) */
    r = tetcomplexinserttet(mesh, vtx1, vtx2, facetvtx, vtx4);
    assert(r);
    
    /* insert the tet (1, 2, 3, f) */
    r = tetcomplexinserttet(mesh, vtx1, vtx2, vtx3, facetvtx);
    assert(r);
    
    /* insert the tet (1, 3, 4, f) */
    r = tetcomplexinserttet(mesh, vtx1, vtx3, vtx4, facetvtx);
    assert(r);
    
    /* if asked, record this flip in the journal */
    if (record)
    {
        insertjournalentry(mesh, FLIP13, verts, 5, (starreal *) NULL, (starreal *) NULL);
    }
}

/* the opposite of a 1-3 flip. Given three tets that share
   a facet vertex and an interior vertex, remove the facet
   vertex and replace them with one tet. vtx1 is the 
   interior vertex, facetvtx is the facet vtx, and 
   the other three vertices are on the future boundary
   facet and will form face (2,3,4) oriented toward vtx1 */
void flip31(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag facetvtx,
            bool record)
{
    int r;
    tag verts[5];
    
    verts[0] = vtx1;
    verts[1] = vtx2;
    verts[2] = vtx3;
    verts[3] = vtx4;
    verts[4] = facetvtx;
    
    /* delete the tet (1, 2, f, 4) */
    r = tetcomplexdeletetet(mesh, vtx1, vtx2, facetvtx, vtx4);
    assert(r);
    
    /* delete the tet (1, 2, 3, f) */
    r = tetcomplexdeletetet(mesh, vtx1, vtx2, vtx3, facetvtx);
    assert(r);
    
    
    /* delete the tet (1, 3, 4, f) */
    r = tetcomplexdeletetet(mesh, vtx1, vtx3, vtx4, facetvtx);
    assert(r);
    
    /* insert the replacement tet */
    r = tetcomplexinserttet(mesh, vtx1, vtx2, vtx3, vtx4);
    assert(r);
    
    /* if asked, record this flip in the journal */
    if (record)
    {
        insertjournalentry(mesh, FLIP31, verts, 5, (starreal *) NULL, (starreal *) NULL);
    }
}

/* given a tetrahedron with a boundary edge and a new vertex that
   lies on that segment, remove the old tet and create two new
   ones. vtx1, vtx2 should be the boundary edge */
void flip12(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag segmentvtx,
            bool record)
{
    int r;
    tag verts[5];
    
    verts[0] = vtx1;
    verts[1] = vtx2;
    verts[2] = vtx3;
    verts[3] = vtx4;
    verts[4] = segmentvtx;
    
    /* delete the original tet */
    r = tetcomplexdeletetet(mesh, vtx1, vtx2, vtx3, vtx4);
    assert(r);
    
    /* insert the tet (1, 3, 4, s) */
    r = tetcomplexinserttet(mesh, vtx1, vtx3, vtx4, segmentvtx);
    assert(r);
    
    /* insert the tet (2, 4, 3, s) */
    r = tetcomplexinserttet(mesh, vtx2, vtx4, vtx3, segmentvtx);
    assert(r);
    
    /* if asked, record this flip in the journal */
    if (record)
    {
        insertjournalentry(mesh, FLIP12, verts, 5, (starreal *) NULL, (starreal *) NULL);
    }
}

/* reverse the above 1-2 flip */
void flip21(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag segmentvtx,
            bool record)
{
    int r;
    tag verts[5];
    
    verts[0] = vtx1;
    verts[1] = vtx2;
    verts[2] = vtx3;
    verts[3] = vtx4;
    verts[4] = segmentvtx;
    
    /* delete the tet (1, 3, 4, s) */
    r = tetcomplexdeletetet(mesh, vtx1, vtx3, vtx4, segmentvtx);
    assert(r);
    
    /* delete the tet (2, 4, 3, s) */
    r = tetcomplexdeletetet(mesh, vtx2, vtx4, vtx3, segmentvtx);
    assert(r);
    
    /* insert the original tet */
    r = tetcomplexinserttet(mesh, vtx1, vtx2, vtx3, vtx4);
    assert(r);
    
    /* if asked, record this flip in the journal */
    if (record)
    {
        insertjournalentry(mesh, FLIP12, verts, 5, (starreal *) NULL, (starreal *) NULL);
    }
}

/* creates the tetrahedra for the optimal triangulation of Tij */
void flip23recurse(struct tetcomplex *mesh,
                   tag vtx1,
                   tag vtx2,
                   tag *ring,
                   int ringcount,
                   int K[][MAXRINGTETS],
                   int i,
                   int j,
                   tag newtets[][4],
                   int *newtetcount)
{
    int k;
    
    /* only triangulate if we have more than an edge */
    if (j >= i+2)
    {
        k = K[i][j];
        flip23recurse(mesh, vtx1, vtx2, ring, ringcount, K, i, k, newtets, newtetcount);
        flip23recurse(mesh, vtx1, vtx2, ring, ringcount, K, k, j, newtets, newtetcount);
        
        /* eliminate the tetrahedra
        
           (vtx1, vtx2, ring[i-1], ring[k-1]) and 
           (vtx1, vtx2, ring[k-1], ring[j-1])
           
           and replace them with the tetrahedra
           
           (vtx1,      ring[i-1], ring[k-1], ring[j-1]),
           (ring[i-1], ring[k-1], ring[j-1], vtx2), and
           (vtx1,      vtx2,      ring[i-1], ring[j-1])
           
           using a 2-3 flip */
        
        /* make sure the two old tets exist */
        assert(tetexists(mesh, vtx1, vtx2, ring[i-1], ring[k-1]) == 1);
        assert(tetexists(mesh, vtx1, vtx2, ring[k-1], ring[j-1]) == 1);
                
        /* tetcomplex23flip(mesh, vtx1, ring[k-1], vtx2, ring[i-1], ring[j-1]); */
        /* use my flip instead until TODO Jonathan fixes his bug */
        flip23(mesh, vtx1, ring[k-1], vtx2, ring[i-1], ring[j-1], true);
        
        /* if we're paranoid, check consistency after every flip */
        /*
        if (1 == 0)
        {
            printf("\nThe vertices in question are:\n");
            printf("v_i=%d\nv_j=%d\nv_k=%d\n  a=%d\n  b=%d\n\n",ring[i-1],ring[j-1],ring[k-1],vtx1,vtx2);
            
            printf("I made sure the following tets existed BEFORE flip:\n");
            printf("a=%d b=%d v_i=%d v_k=%d\n", vtx1, vtx2, ring[i-1], ring[k-1]);
            printf("a=%d b=%d v_k=%d v_j=%d\n\n", vtx1, vtx2, ring[k-1], ring[j-1]);
            
            printf("I called tetcomplex23flip with \nvtx1=a \nvtx2=v_k \nvtx3=b \nvtx_bot=v_i \nvtx_top=v_j\n\n");
            
            printf("I made sure the following tets existed AFTER flip:\n");
            printf("  a=%d v_i=%d v_k=%d v_j=%d\n", vtx1, ring[i-1], ring[k-1], ring[j-1]);
            printf("v_i=%d v_k=%d v_j=%d   b=%d\n", ring[i-1], ring[k-1], ring[j-1], vtx2);
            printf("  a=%d   b=%d v_i=%d v_j=%d\n\n", vtx1, vtx2, ring[i-1], ring[j-1]);
            
            printf("And now, let's check consistency:\n");
            assert(tetcomplexconsistency(mesh) == 1);
        }
        */
        
        /* make sure the three new tets exist, and the permanent one are rightside out*/
        assert(tetexists(mesh, vtx1, ring[i-1], ring[k-1], ring[j-1]) == 1);
        assert(tetexists(mesh, ring[i-1], ring[k-1], ring[j-1], vtx2) == 1);
        assert(tetexists(mesh, vtx1, vtx2, ring[i-1], ring[j-1]) == 1);
        assert(tetquality(mesh, vtx1, ring[i-1], ring[k-1], ring[j-1], improvebehave.qualmeasure) > 0);
        assert(tetquality(mesh, ring[i-1], ring[k-1], ring[j-1], vtx2, improvebehave.qualmeasure) > 0);
        
        /* record the 2 permanent new tets */
        (*newtetcount)++;
        newtets[(*newtetcount)-1][0] = vtx1;
        newtets[(*newtetcount)-1][1] = ring[i-1];
        newtets[(*newtetcount)-1][2] = ring[k-1];
        newtets[(*newtetcount)-1][3] = ring[j-1];
        
        (*newtetcount)++;
        newtets[(*newtetcount)-1][0] = ring[i-1];
        newtets[(*newtetcount)-1][1] = ring[k-1];
        newtets[(*newtetcount)-1][2] = ring[j-1];
        newtets[(*newtetcount)-1][3] = vtx2;
    }
}

/* Replaces all tetrahedra that include the edge from vtx1 to vtx2 with
   the tetrahedra induced by the optimal triangulation of the ring of 
   vertices around that egde, computed by filltables. K is a table of 
   indices that identify the optimal triangulations of every subset of 
   the ring Tij. */
void removeedgeflips(struct tetcomplex *mesh,
                     tag vtx1,
                     tag vtx2,
                     tag *ring,
                     int ringcount,
                     int K[][MAXRINGTETS],
                     tag newtets[][4],
                     int *newtetcount,
                     bool boundary)
{
    /* k <= K[1,m] */
    int k = K[1][ringcount];
    flip23recurse(mesh, vtx1, vtx2, ring, ringcount, K, 1, k, newtets, newtetcount);
    flip23recurse(mesh, vtx1, vtx2, ring, ringcount, K, k, ringcount, newtets, newtetcount);
    
    if (boundary == false)
    {
        /* remove edge vtx1 vtx2 with a 3-2 flip, creating the tetrahedra
           (vtx1, ring[0], ring[k-1], ring[ringcount-1]) and
           (ring[0], ring[k-1], ring[ringcount-1], vtx2) */
        /* using my function instead of Jonathans TODO switch back? */
        /* tetcomplex32flip(mesh, ring[0], ring[k-1], ring[ringcount-1], vtx2, vtx1); */
        flip32(mesh, ring[0], ring[k-1], ring[ringcount-1], vtx2, vtx1, true);
    }
    else
    {
        /* because this is a boundary edge, we remove the edge with a 2-2 flip,
        */
        flip22(mesh, vtx2, vtx1, ring[k-1], ring[0], ring[ringcount-1], true);
    }
    
    /* make sure the new tets exist */
    assert(tetexists(mesh, vtx1, ring[0], ring[k-1], ring[ringcount-1]) == 1);
    assert(tetexists(mesh, ring[0], ring[k-1], ring[ringcount-1], vtx2) == 1);
    
    /* record the last 2 new tets */
    (*newtetcount)++;
    newtets[(*newtetcount)-1][0] = vtx1;
    newtets[(*newtetcount)-1][1] = ring[0];
    newtets[(*newtetcount)-1][2] = ring[k-1];
    newtets[(*newtetcount)-1][3] = ring[ringcount-1];
    
    (*newtetcount)++;
    newtets[(*newtetcount)-1][0] = ring[0];
    newtets[(*newtetcount)-1][1] = ring[k-1];
    newtets[(*newtetcount)-1][2] = ring[ringcount-1];
    newtets[(*newtetcount)-1][3] = vtx2;
}

/* fill Q and K tables for Klincsek's algorithm */
void filltables(struct tetcomplex *mesh,
                tag vtx1,
                tag vtx2,
                tag *ring,
                int ringcount,
                starreal oldminqual,
                starreal Q[][MAXRINGTETS],
                int K[][MAXRINGTETS])
{
    int i, j, k;   /* loop indices */
    starreal quala, qualb; /* qualities of new tets with verts a and b */
    starreal q;            /* quality for current table entry */
    int numboundverts;  /* number of boundary vertices in new tets */
    tag boundtags[4]; 
    
    /* for i <= m-2 downto 1 */
    for (i=ringcount-2; i>=1; i--)
    {
        /* for j <= i+2 to m */
        for (j=i+2; j<=ringcount; j++)
        {
            /* for k <= i+1 to j-1 */
            for (k=i+1; k<=j-1; k++)
            {
                if (improvebehave.verbosity > 6)
                {
                    printf("In filltables, i=%d j=%d k=%d\n",i,j,k);
                }
                
                /* q <= min(quality(a,vi,vj,vk),quality(vi,vk,vj,b)) */
                quala = tetquality(mesh, vtx1, ring[i-1], ring[k-1], ring[j-1], improvebehave.qualmeasure);
                
                /* check whether this new tet will have four boundary verts.
                   if it does, we don't want to create this tet unless it's
                   quality is awesome because it can't be later improved */
                if (quala > oldminqual && quala < MIN4BOUNDQUAL)
                {
                    numboundverts = boundverts(mesh, vtx1, ring[i-1], ring[k-1], ring[j-1], boundtags);
                    if (numboundverts == 4)
                    {
                        if (improvebehave.verbosity > 5)
                        {
                            printf("discovered a potential 4-node-on-boundary tet with qual %g, oldminqual was %g\n",pq(quala),pq(oldminqual));
                        }
                        quala = -1.0;
                    }
                }
                
                qualb = tetquality(mesh, ring[i-1], ring[k-1], ring[j-1], vtx2, improvebehave.qualmeasure);
                
                /* check whether this new tet will have four boundary verts.
                   if it does, we don't want to create this tet unless it's
                   quality is awesome because it can't be later improved */
                if (qualb > oldminqual && qualb < MIN4BOUNDQUAL)
                {
                    numboundverts = boundverts(mesh, ring[i-1], ring[k-1], ring[j-1], vtx2, boundtags);
                    if (numboundverts == 4)
                    {
                        if (improvebehave.verbosity > 5)
                        {
                            printf("discovered a potential 4-node-on-boundary tet with qual %g, oldminqual was %g\n",pq(qualb),pq(oldminqual));
                        }
                        qualb = -1.0;
                    }
                }
                
                q = (quala < qualb) ? quala : qualb;
                
                if (k < j-1)
                {
                    q = (q < Q[k][j]) ? q : Q[k][j];
                }
                if (k > i+1)
                {
                    q = (q < Q[i][j]) ? q : Q[i][j];
                }
                if ((k == i+1) || (q > Q[i][j]))
                {
                    Q[i][j] = q;
                    K[i][j] = k;
                }
            }
        }
    }
}

/* try contracting the edge from v1 to v2 that is in the
   tet (v1, v2, v3, v4). Return true if edge contraction
   succeeds in improving quality of all affected tets,
   and false otherwise (mesh unchanged on failure) */
#define CONTRACTPARANOID false
bool edgecontract(struct tetcomplex *mesh,
                  tag v1,
                  tag v2,
                  tag v3,
                  tag v4,
                  starreal *minqualbefore,
                  starreal *minqualafter,
                  int *numouttets,
                  tag outtets[MAXINCIDENTTETS][4],
                  bool requireimprove)
{
    bool boundedge;               /* is this a boundary edge? */
    int numringtets;              /* number of tets in the ring around the edge */
    tag ringtets[MAXRINGTETS][4]; /* the tets in the ring */
    tag boundfacev[2];            /* vertices of faces on the boundary */
    tag tet[4], newtet[4];        /* tet arranged so less flexible vert is first */
    int i,j;                      /* loop index */
    starreal quality;             /* current tet quality */
    bool smoothed;                /* was vertex smoothing successful */
    starreal smoothqual;          /* quality after smoothing */
    int smoothkinds = 0;          /* types of vertices that can be smoothed */
    starreal e[3];                /* vector of the edge */
    starreal *segment;            /* pointer to vertex's free segment, if any */
    starreal *v1c, *v2c;          /* pointers to vertex coordinates */
    starreal edgedot=0.0;         /* dot product between edge vector and segment */
    starreal worstnewqual=HUGEFLOAT;/* worst quality of new tets before smoothing */
    starreal worstafter;
    tag toinsert[MAXINCIDENTTETS][4];
    int numtoinsert = 0;
    int edge[2];
    starreal thislong;
    
    int edgecase = NOEDGECASE;
    
    /* get global worst for paranoid insertion */
    starreal worstbefore = HUGEFLOAT;
    starreal meanquals[NUMMEANTHRESHOLDS];
    
    /* a list of all the tets incident to the edge vertices */
    int numincident[2];
    tag incidenttags[2][MAXINCIDENTTETS][4];
    bool noghosts;
    
    /* save the mesh state before we start changing stuff */
    int beforeid = lastjournalentry();
    
    /* determine the vertex type of each endpoint */
    int v1type = ((struct vertextype *) arraypoollookup(&vertexinfo, v1))->kind;
    int v2type = ((struct vertextype *) arraypoollookup(&vertexinfo, v2))->kind;
    assert(v1type != INPUTVERTEX && v2type != INPUTVERTEX);
    if (CONTRACTPARANOID)
    {
        meshquality(mesh, improvebehave.qualmeasure, meanquals, &worstbefore);
    }
    
    if (improvebehave.facetsmooth) smoothkinds |= SMOOTHFACETVERTICES;
    if (improvebehave.segmentsmooth) smoothkinds |= SMOOTHSEGMENTVERTICES;
    if (improvebehave.fixedsmooth) smoothkinds |= SMOOTHFIXEDVERTICES;
    
    /* TODO: take this out? give up with any fixed vertices */
    /*
    if (v1type == FIXEDVERTEX || v2type == FIXEDVERTEX)
    {
        return false;
    }
    */
    
    /* determine which contraction case we're dealing with */
    if (v1type == FREEVERTEX || v2type == FREEVERTEX)
    {
        if (v1type == FREEVERTEX && v2type == FREEVERTEX)
        {
            edgecase = FREEFREEEDGE;
        }
        else if (v1type == FACETVERTEX || v2type == FACETVERTEX)
        {
            edgecase = FREEFACETEDGE;
        }
        else if (v1type == SEGMENTVERTEX || v2type == SEGMENTVERTEX)
        {
            edgecase = FREESEGMENTEDGE;
        }
        else
        {
            assert(v1type == FIXEDVERTEX || v2type == FIXEDVERTEX);
            edgecase = FREEFIXEDEDGE;
        }
    }
    /* neither vertex is free */
    else if (v1type == FACETVERTEX || v2type == FACETVERTEX)
    {
        if (v1type == FACETVERTEX && v2type == FACETVERTEX)
        {
            edgecase = FACETFACETEDGE;
        }
        else if (v1type == SEGMENTVERTEX || v2type == SEGMENTVERTEX)
        {
            edgecase = FACETSEGMENTEDGE;
        }
        else
        {
            assert(v1type == FIXEDVERTEX || v2type == FIXEDVERTEX);
            edgecase = FACETFIXEDEDGE;
        }
    }
    /* nor is either vertex facet */
    else if (v1type == SEGMENTVERTEX || v2type == SEGMENTVERTEX)
    {
        if (v1type == SEGMENTVERTEX && v2type == SEGMENTVERTEX)
        {
            edgecase = SEGMENTSEGMENTEDGE;
        }
        else
        {
            assert(v1type == FIXEDVERTEX || v2type == FIXEDVERTEX);
            edgecase = SEGMENTFIXEDEDGE;
        }
    }
    /* nor is either vertex segment */
    else
    {
        assert(v1type == FIXEDVERTEX && v2type == FIXEDVERTEX);
        edgecase = FIXEDFIXEDEDGE;
    }
    assert(edgecase != NOEDGECASE);
    
    /* gather tets around edge and check if it's on the boundary */
    boundedge = getedgering(mesh, v1, v2, v3, v4, &numringtets, ringtets, boundfacev);
    
    if (improvebehave.verbosity > 5)
    {
        printf("At start of edgecontract, lastjournalid = %d\n", beforeid);
        printf("In edge contraction, v1type = %d, v2type = %d, boundedge=%d\n", v1type, v2type, boundedge);
    }
    
    /* if one of the vertices is a segment vertex, figure out edge vector */
    if (edgecase == SEGMENTSEGMENTEDGE || edgecase == SEGMENTFIXEDEDGE)
    {
        if (v1type == SEGMENTVERTEX)
        {
            /* fetch the pre-computed vertex segment vector */
            segment = ((struct vertextype *) arraypoollookup(&vertexinfo, v1))->vec;
        }
        else
        {
            assert(v2type == SEGMENTVERTEX);
            /* fetch the pre-computed vertex segment vector */
            segment = ((struct vertextype *) arraypoollookup(&vertexinfo, v2))->vec;
        }
        /* compute the normalized edge vector between the two vertices */
        v1c = ((struct vertex *) tetcomplextag2vertex(mesh, v1))->coord;
        v2c = ((struct vertex *) tetcomplextag2vertex(mesh, v2))->coord;
        
        vsub(v2c, v1c, e);
        vscale(1.0 / vlength(e), e, e);
        
        edgedot = dot(e, segment);
        
        if (improvebehave.verbosity > 5)
        {
            printf("segment is (%g %g %g), edge vector is (%g %g %g), dot product is %g\n", segment[0], segment[1], segment[2], e[0], e[1], e[2], edgedot);
        }
    }
    
    /* handle the weirdness of each case */
    switch (edgecase)
    {
        case FREEFREEEDGE:
            if (improvebehave.verbosity > 5)
            {
                printf("    case is free-free contraction.\n");
            }
            break;
        case FREEFACETEDGE:
            if (improvebehave.verbosity > 5)
            {
                printf("    case is free-facet contraction\n");
            }
            break;
        case FREESEGMENTEDGE:
            if (improvebehave.verbosity > 5)
            {
                printf("    case is free-segment contraction\n");
            }
            break;
        case FREEFIXEDEDGE:
            if (improvebehave.verbosity > 5)
            {
                printf("    case is free-fixed contraction\n");
            }
            break;
        case FACETFACETEDGE:
            if (improvebehave.verbosity > 5)
            {
                printf("    case is facet-facet contraction\n");
            }
            /* for this case, if the edge is not a boundary edge, no-go */
            if (!boundedge)
            {
                if (improvebehave.verbosity > 5) printf("    FAILS because edge is not boundary edge.\n");
                return false;
            }
            break;
        case FACETSEGMENTEDGE:
            if (improvebehave.verbosity > 5)
            {
                printf("    case is facet-segment contraction.\n");
            }
            if (!boundedge)
            {
                if (improvebehave.verbosity > 5) printf("    FAILS because edge is not boundary edge.\n");
                return false;
            }
            break;
        case FACETFIXEDEDGE:
            return false;
            if (improvebehave.verbosity > 5)
            {
                /* make sure its a boundary edge */
                if (!boundedge)
                {
                    if (improvebehave.verbosity > 5) printf("    FAILS because edge is not boundary edge.\n");
                    return false;
                }
                printf("    case is facet-fixed contraction.\n");
            }
            break;
        case SEGMENTSEGMENTEDGE:
            if (improvebehave.verbosity > 5)
            {
                printf("    case is segment-segment contraction.\n");
            }
            /* make sure its a boundary edge */
            if (!boundedge)
            {
                if (improvebehave.verbosity > 5) printf("    FAILS because edge is not boundary edge.\n");
                return false;
            }
            /* make sure that the segment and the edge are the same */
            if (fabs(edgedot) != 1.0)
            {
                if (improvebehave.verbosity > 5) printf("   FAILS because edge and segment aren't the same.\n");
                return false;
            }
            break;
        case SEGMENTFIXEDEDGE:
            return false;
            if (improvebehave.verbosity > 5)
            {
                printf("    case is segment-fixed contraction.\n");
            }
            /* make sure its a boundary edge */
            if (!boundedge)
            {
                if (improvebehave.verbosity > 5) printf("    FAILS because edge is not boundary edge.\n");
                return false;
            }
            if (fabs(edgedot) != 1.0)
            {
                if (improvebehave.verbosity > 5) printf("   FAILS because edge and segment aren't the same.\n");
                return false;
            }
            break;
        case FIXEDFIXEDEDGE:
            if (improvebehave.verbosity > 5)
            {
                printf("    case is fixed-fixed contraction. NOT SUPPORTED.\n");
            }
            return false;
            break;
        default:
            printf("Invalid edge contraction case %d. Dying.\n", edgecase);
            starexit(1);
            break;
    }
    
    /* if v2 has less freedom than v1 */
    if (v2type < v1type)
    {
        /* arrange the tet so v2 goes first */
        tet[0] = v2;
        tet[1] = v1;
        tet[2] = v4;
        tet[3] = v3;
    }
    else
    {
        /* arrange thet tet so v1 goes first */
        tet[0] = v1;
        tet[1] = v2;
        tet[2] = v3;
        tet[3] = v4;
    }
    assert(tetexistsa(mesh, tet));
    
    if (improvebehave.verbosity > 5)
    {
        printf("Going ahead. v1=%d, type=%d, v2=%d, type=%d, tet[0]=%d, tet[1]=%d\n", (int) v1, v1type, (int) v2, v2type, (int) tet[0], (int) tet[1]);
    }
    
    /* fetch all the tets incident to each endpoint and compute minimum quality */
    *minqualbefore = HUGEFLOAT;
    numincident[0] = numincident[1] = 0;
    getincidenttets(mesh, tet[0], tet[1], tet[2], tet[3],
                    incidenttags[0], &numincident[0], &noghosts);
    getincidenttets(mesh, tet[1], tet[0], tet[3], tet[2],
                    incidenttags[1], &numincident[1], &noghosts);
    
    for (i=0; i<2; i++)
    {                   
        for (j=0; j<numincident[i]; j++)
        {
            quality = tetquality(mesh, 
                                 incidenttags[i][j][0],
                                 incidenttags[i][j][1],
                                 incidenttags[i][j][2],
                                 incidenttags[i][j][3],
                                 improvebehave.qualmeasure);
            if (quality < *minqualbefore) *minqualbefore = quality;
        }
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("In edge contract, v1=%d has %d tets incident, v2=%d has %d tets\n", (int) tet[0], numincident[0], (int) tet[1], numincident[1]);
        printf("Minimum quality before contraction is %g\n", pq(*minqualbefore));
    }
    
    stats.edgecontractionattempts++;
    stats.edgecontractringatt[numringtets]++;
    stats.edgecontractcaseatt[edgecase]++;
    
    /* delete all tets in the ring around the edge */
    for (i=0; i<numringtets; i++)
    {
        assert(tetexistsa(mesh, ringtets[i]));
        deletetet(mesh, ringtets[i][0], ringtets[i][1], ringtets[i][2], ringtets[i][3], true);
        /*
        printf("    just deleted ring tet %d/%d (%d %d %d %d)\n", i+1, numringtets, ringtets[i][0], ringtets[i][1], ringtets[i][2], ringtets[i][3]);
        */
    }
    
    newtet[0] = GHOSTVERTEX;
    newtet[1] = GHOSTVERTEX;
    newtet[2] = GHOSTVERTEX;
    newtet[3] = GHOSTVERTEX;
    
    /* replace all the tets incident to the second endpoint with tets inc. to first */
    for (i=0; i<numincident[1]; i++)
    {
        /* check that this tet wasn't deleted with ring tets */
        if (!tetexistsa(mesh, incidenttags[1][i])) 
        {
            if (improvebehave.verbosity > 5)
            {
                printf("    Skipping deletion of incident tet (%d %d %d %d), it's already gone\n", (int) incidenttags[1][i][0], (int) incidenttags[1][i][1], (int) incidenttags[1][i][2], (int) incidenttags[1][i][3]);
            }
            continue;
        }
        
        /* if we're anisotropic, check the quality in physical space */
        if (improvebehave.anisotropic)
        {
            improvebehave.anisotropic = false;
            
            quality = tetquality(mesh,
                           tet[0],
                           incidenttags[1][i][1],
                           incidenttags[1][i][2],
                           incidenttags[1][i][3],
                           improvebehave.qualmeasure);
                           
            improvebehave.anisotropic = true;
            
            if (quality <= MINSIZETETQUALITY)
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("Can't contract edge because IN PHYSICAL SPACE a new tet would invert.\n");
                }

                /* undo what we've done and return failure */
                invertjournalupto(mesh, beforeid);
                return false;
            }
        }
        
        /* check if the new tet would be inverted. if so, give up */
        quality = tetquality(mesh,
                       tet[0],
                       incidenttags[1][i][1],
                       incidenttags[1][i][2],
                       incidenttags[1][i][3],
                       improvebehave.qualmeasure);
        if (quality <= MINTETQUALITY)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("Can't contract edge because a new tet would invert.\n");
            }
            
            /* undo what we've done and return failure */
            invertjournalupto(mesh, beforeid);
            return false;
        }
        
        /* if this is the worst inserted tet note it */
        if (quality < worstnewqual) worstnewqual = quality;
        
        if (improvebehave.verbosity > 5)
        {
            printf("    Replacing tet (%d %d %d %d) with tet (%d %d %d %d)\n", 
            (int) incidenttags[1][i][0],
            (int) incidenttags[1][i][1],
            (int) incidenttags[1][i][2],
            (int) incidenttags[1][i][3],
            (int) tet[0],
            (int) incidenttags[1][i][1],
            (int) incidenttags[1][i][2],
            (int) incidenttags[1][i][3]);
        }
        
        deletetet(mesh, 
                  incidenttags[1][i][0],
                  incidenttags[1][i][1],
                  incidenttags[1][i][2],
                  incidenttags[1][i][3],
                  true);
        
        toinsert[numtoinsert][0] = tet[0];
        toinsert[numtoinsert][1] = incidenttags[1][i][1];
        toinsert[numtoinsert][2] = incidenttags[1][i][2];
        toinsert[numtoinsert][3] = incidenttags[1][i][3];
        numtoinsert++; 
    }
    
    if (improvebehave.verbosity > 5 || worstnewqual < MINTETQUALITY)
    {
        printf("Replacing %d tets incident to vertex %d\n", numtoinsert, (int) tet[1]);
        printf("Worst inserted tet quality is %g\n", pq(worstnewqual));
    }
    
    /* the number of tets to insert should be the number incident to the second vertex
       less the number of ring vertices */
    assert(numtoinsert == numincident[1] - numringtets);
    
    /* need a separate loop so all are deleted before insertion ? */
    for (i=0; i<numtoinsert; i++)
    {
        /*
        printf("about to insert tet (%d %d %d %d)\n", toinsert[i][0], toinsert[i][1], toinsert[i][2], toinsert[i][3]);
        */
        inserttet(mesh, 
                  toinsert[i][0],
                  toinsert[i][1],
                  toinsert[i][2],
                  toinsert[i][3],
                  true);
        /* record the most recently inserted tet */
        newtet[0] = toinsert[i][0];
        newtet[1] = toinsert[i][1];
        newtet[2] = toinsert[i][2];
        newtet[3] = toinsert[i][3];
        /* make sure we have an extant tet to base the smooth off of */
        assert(tetexistsa(mesh, newtet));
    }
    
    if (worstnewqual < MINTETQUALITY)
    {
        printf("in edge contract, worst new qual = %g is below mintetquality\n", worstnewqual);
    }
    assert(worstnewqual >= MINTETQUALITY);
    
    /* now, smooth the remaining endpoint */
    smoothed = nonsmoothsinglevertex(mesh,
                                         newtet[0],
                                         newtet[1],
                                         newtet[2],
                                         newtet[3],
                                         &smoothqual,
                                         smoothkinds);
    /* if smoothing was successful, then use its worst qual */
    if (smoothed)
    {
        *minqualafter = smoothqual;
    }
    /* otherwise, use the worst new tet */
    else
    {
        if (improvebehave.verbosity > 5)
        {
            printf("using worst inserted quality rather than smoothed quality!");
        }
        *minqualafter = worstnewqual;
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("After edge contraction and smoothing, worst qual went from %g to %g, diff of %g\n", pq(*minqualbefore), pq(smoothqual), pq(smoothqual - *minqualbefore));
    }
    
    /* enforce minimum improvement */
    if ((*minqualafter - *minqualbefore < MINCONTRACTIMPROVEMENT) && requireimprove)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("Reverting edge contraction because quality worsened.\n");
        }
        invertjournalupto(mesh, beforeid);
        return false;
    }
    
    if (!requireimprove && (*minqualafter < MINCONTRACTQUAL))
    {
        if (improvebehave.verbosity > 5)
        {
            printf("Aborting size-control edge contraction because worst new qual is %g (%g required)\n", *minqualafter, MINCONTRACTQUAL);
        }
        invertjournalupto(mesh, beforeid);
        return false;
    }
    
    /* collect tets incident to the remaining vertex and return them */
    if (numouttets != NULL)
    {
        *numouttets = 0;
        getincidenttets(mesh, newtet[0], newtet[1], newtet[2], newtet[3],
                        outtets, numouttets, &noghosts);
        
        /* check to make sure that none of the edges are too short or too long */
        if (improvebehave.sizing)
        {
            for (i=0; i<(*numouttets); i++)
            {
                thislong = tetedge(mesh, outtets[i][0], outtets[i][1], outtets[i][2], outtets[i][3], edge, true);
                if (thislong > improvebehave.targetedgelength * improvebehave.longerfactor * 0.7)
                {
                    if (improvebehave.verbosity > 5)
                    {
                        printf("Aborting edge contraction because it would create edge %g long, longest allowable is %g\n", thislong, improvebehave.targetedgelength * improvebehave.longerfactor * 0.85);
                    }
                    invertjournalupto(mesh, beforeid);
                    return false;
                }
            }
        }
        
        if (improvebehave.verbosity > 5)
        {
            textcolor(BRIGHT, GREEN, BLACK);
            printf("Edge contraction succeeded. %d tets deleted. %d tets now incident.\n", numringtets, *numouttets);
            printf("After edge contraction and smoothing=%d, worst qual went from %g to %g, diff of %g\n", smoothed, pq(*minqualbefore), pq(smoothqual), pq(smoothqual - *minqualbefore));
            textcolor(RESET, WHITE, BLACK);
        }
    
        /* the number of tets incident to the surviving vertex should be
           the sum of those incident to the original edge endpoints minus the number
           of tets in the ring */
        assert(*numouttets == numincident[0] + numincident[1] - (2 * numringtets));
    }
    
    worstafter = HUGEFLOAT;
    if (CONTRACTPARANOID)
    {
        meshquality(mesh, improvebehave.qualmeasure, meanquals, &worstafter);
        printf("worstbefore = %g, worstafter = %g, diff %g\n", pq(worstbefore), pq(worstafter), pq(worstafter - worstbefore));
        if (worstafter < worstbefore)
        {
            worsttetreport(mesh, improvebehave.qualmeasure, 1.0);
        }
        assert(worstafter >= worstbefore);
    }
    
    /* record success */
    stats.edgecontractions++;
    stats.edgecontractringsuc[numringtets]++;
    stats.edgecontractcasesuc[edgecase]++;
    
    if (edgecase == FACETFIXEDEDGE)
    {
        printf("Whoa, facet fixed worked!\n");
    }
    if (edgecase == SEGMENTFIXEDEDGE)
    {
        printf("Whee, segment fixed worked!\n");
    }
    
    return true;
}

/* try to contract all six edges of a tet */
bool tryedgecontract(struct tetcomplex *mesh,
                     tag vtx1, tag vtx2, tag vtx3, tag vtx4,
                     struct arraypoolstack *outstack,
                     starreal *minqualafter,
                     bool requireimprove,
                     bool justfirstedge)
{
    tag tet[4];
    bool contracted = false;
    starreal minqualbefore;
    int numouttets;
    tag outtets[MAXINCIDENTTETS][4];
    struct improvetet *stacktet;
    int i,j,k,l,m,temp;
    starreal newqual;
    
    /* first, check to make sure this tet still exists in the mesh */
    if (tetexists(mesh, vtx1, vtx2, vtx3, vtx4) == 0)
    {
        return false;
    }
    
    tet[0] = vtx1;
    tet[1] = vtx2;
    tet[2] = vtx3;
    tet[3] = vtx4;
    
    if (improvebehave.verbosity > 5)
    {
        printf("** Starting tryedgecontract on top-level tet (%d %d %d %d)\n", (int) vtx1, (int) vtx2, (int) vtx3, (int) vtx4);
    }
    
    /* loop over all 6 edges of the tetrahedron */
    for (i = 0; i < 3; i++) 
    {
        for (j = i + 1; j < 4; j++) 
        {
            k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
            l = 6 - i - j - k;
            /* to get right sequence, need to swap k and l sometimes */
            if ((i+j) % 2 == 0)
            {
                temp = k;
                k = l;
                l = temp;
            }
            
            if (improvebehave.verbosity > 5)
            {
                printf("About to attempt edge contraction on tet (%d %d %d %d)\n", (int) tet[i], (int) tet[j], (int) tet[k], (int) tet[l]);
            }
            
            contracted = edgecontract(mesh, tet[i], tet[j], tet[k], tet[l],
                                      &minqualbefore, minqualafter,
                                      &numouttets, outtets, requireimprove);
            
            /* if contraction fails, try with order swapped */
            if (contracted == false)
            {
                contracted = edgecontract(mesh, tet[j], tet[i], tet[l], tet[k],
                                          &minqualbefore, minqualafter,
                                          &numouttets, outtets, requireimprove);
            }
            
            /* if edge contraction succeeded */
            if (contracted)
            {
                if (outstack != NULL)
                {
                    if (improvebehave.verbosity > 5)
                    {
                        printf("Pushing %d new tets on the output stack\n", numouttets);
                    }
                    
                    for (m=0; m<numouttets; m++)
                    {
                        assert(tetexistsa(mesh, outtets[m]));
                        newqual = tetquality(mesh, 
                                             outtets[m][0],
                                             outtets[m][1],
                                             outtets[m][2],
                                             outtets[m][3],
                                             improvebehave.qualmeasure);
                        assert(newqual > 0);
                        
                        /* push this tet on the output stack */
                        if (tetinstack(outstack,
                                       outtets[m][0],
                                       outtets[m][1],
                                       outtets[m][2],
                                       outtets[m][3]) == false)
                        {
                            stacktet = (struct improvetet *) stackpush(outstack);
                            stacktet->quality = newqual;
                            stacktet->verts[0] = outtets[m][0];
                            stacktet->verts[1] = outtets[m][1];
                            stacktet->verts[2] = outtets[m][2];
                            stacktet->verts[3] = outtets[m][3];
                        }
                    }
                }
                
                /* return with success */
                return true;
            }
            
            /* if we're requested just to try the first edge, bail now */
            if (justfirstedge) return false;
        }
    }
    
    return false;
}

/* attempt to remove the edge from vtx1 to vtx2. ring is the ring
   of vertices to be removed. Return 1 if edge removal successfully
   improves quality, zero otherwise. */
int removeedge(struct tetcomplex *mesh, 
               tag vtx1,
               tag vtx2,
               tag* ring,
               int ringcount,
               starreal oldminqual,
               tag newtets[][4],
               int *newtetcount,
               starreal *outminqual,
               bool boundary)
{
    static starreal Q[MAXRINGTETS][MAXRINGTETS]; /* table to hold minimal quality of each subtraingluation */
    static int K[MAXRINGTETS][MAXRINGTETS];    /* table to hold pointer to optimal subtriangulations */
    starreal newminqual;                   /* minimum tet quality in the new triangulation */
    
    /* fill the tables */
    filltables(mesh, vtx2, vtx1, ring, ringcount, oldminqual, Q, K);
    
    /* retrieve the minimum quality of the new triangulation */
    newminqual = Q[1][ringcount];
    
    if (improvebehave.verbosity > 5 && (newminqual > oldminqual))
    {
        printf("new configuration for edge remove with quality %f better than old %f...\n", pq(newminqual), pq(oldminqual));
        printtables(Q, K, ringcount);
    }
    
    /* if we have an improvement in quality, remove the edge */
    if (newminqual > oldminqual)
    {
        removeedgeflips(mesh, vtx2, vtx1, ring, ringcount, K, newtets, newtetcount, boundary);
        *outminqual = newminqual;
        return 1;
    }
    else
    {
        *outminqual = oldminqual;
        return 0;
    }
}

/* check for any boundary edge removal opportunities in this tet. */
int tryboundaryedgeremove(struct tetcomplex *mesh,
                   tag vtx1,
                   tag vtx2,
                   tag vtx3,
                   tag vtx4,
                   struct arraypoolstack *tetstack,
                   int ringsizes[MAXRINGTETS],
                   int *biggestring,
                   starreal *minafterqual)
{
    int numboundedges;
    tag edgelist[6][2];
    tag edgefaces[6][2]; /* the third vertex in the faces that lie on the boundary */
    int numedgetets[6];
    tag edgetets[6][MAXRINGTETS][4];
    int i,j;
    tag v1, v2, v3, v4; /* tags of vertices of two faces */
    starreal *vc1, *vc2, *vc3, *vc4; /* coordinates of the face vertices */
    starreal e1[3], e2[3], e3[3];   /* edges for forming cross products */
    starreal norm1[3], norm2[3];     /* normals for the two faces */
    starreal dotprod;
    starreal minbeforequal=HUGEFLOAT, curqual, newqual;
    tag newtets[MAXRINGTETS][4];  /* array to hold the new submesh after edge flipping */
    tag vertring[MAXRINGTETS];    /* half-ring of vertices around edge */
    int newtetcount = 0;          /* number of tets in new arrangement */
    bool edgeremoved = false;
    struct improvetet *stacktet;  /* for pushing newly created tets on the stack */
    bool foundface;
    tag nextprev[2];
    int ringsize;
    
    /* fetch all the boundary edges of this tet and their rings of tets */
    numboundedges = boundedges(mesh,
                               vtx1, vtx2, vtx3, vtx4,
                               edgelist,
                               edgefaces,
                               numedgetets,
                               edgetets);
                               
    if (numboundedges == 0) return 0;
    
    /* try each boundary edge */
    for (i=0; i<numboundedges; i++)
    {
        /* check if this edge's two boundary faces are in a plane,
           which makes the edge eligible for removal */
        
        v1 = edgelist[i][0]; /* first vertex of edge to be removed */
        v2 = edgelist[i][1]; /* second vertex of edge to be removed */
        v3 = edgefaces[i][0]; /* third vertex of first face */
        v4 = edgefaces[i][1]; /* third vertex of second face */
        
        /* fetch actual vertex coordinates */
        vc1 = ((struct vertex *) tetcomplextag2vertex(mesh, v1))->coord;
        vc2 = ((struct vertex *) tetcomplextag2vertex(mesh, v2))->coord;
        vc3 = ((struct vertex *) tetcomplextag2vertex(mesh, v3))->coord;
        vc4 = ((struct vertex *) tetcomplextag2vertex(mesh, v4))->coord;
        
        /* form edge vectors for the faces */
        vsub(vc2, vc1, e1);
        vsub(vc3, vc1, e2);
        vsub(vc4, vc1, e3);
         
        /* find the (unit-length) face normal of this face */
        cross(e1, e2, norm1);
        vscale((1.0 / vlength(norm1)), norm1, norm1);
        cross(e3, e1, norm2);
        vscale((1.0 / vlength(norm2)), norm2, norm2);
        
        /* compute dot product between two face normals to determine if
           faces are coplanar */
        dotprod = dot(norm1, norm2);
        
        /* we need to be exact about dot product so as not to create inverted tets */
        if (dotprod != 1.0)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("edge is not in facet because dotprod = %g\n", dotprod);
            }
            
            /* this edge doesn't lie in an input face, and can't be removed */
            continue; /* move on to the next boundary edge */
        }
        
        if (improvebehave.verbosity > 5)
        {
            printf("edge IS  in facet because dotprod = %g\n", dotprod);
        }
        
        /* debug output to visualize coplanar faces */
        /*
        if (improvebehave.verbosity > 5)
        {
            tag faces[2][3] = {{v1,v2,v3},{v1,v4,v2}};
            printf("here are the coplanar faces:\n");
            printfaces(mesh, faces, 2);
            printf("here are the tets halfway around edge\n");
            printtets(mesh, edgetets[i], numedgetets[i]);
        }
        */
        
        /* compute minimum quality of tets around half-ring originally */
        for (j=0; j<numedgetets[i]; j++)
        {
            curqual = tetquality(mesh, 
                                 edgetets[i][j][0], 
                                 edgetets[i][j][1], 
                                 edgetets[i][j][2], 
                                 edgetets[i][j][3],
                                 improvebehave.qualmeasure);
            if (curqual < minbeforequal) minbeforequal = curqual;
        }
        
        /* build up half-ring of verts */
        vertring[0] = v4;
        ringsize = 1;
        foundface = tetcomplexadjacencies(mesh, v1, v2, vertring[0], nextprev);
        assert(foundface);
        assert(nextprev[0] != GHOSTVERTEX);
        /* move around the ring using adjacency queries */
        while (nextprev[0] != GHOSTVERTEX)
        {
            /* add the next vertex to the ring */
            vertring[ringsize] = nextprev[0];
            ringsize++;
            
            foundface = tetcomplexadjacencies(mesh, v1, v2, vertring[ringsize-1], nextprev);
            assert(foundface);
        }
        /* at the end, the last ring vertex should be v3... */
        assert(vertring[ringsize-1] == v3);
        
        if (improvebehave.verbosity > 5)
        {
            printf("there are %d verts in half-ring\n", ringsize);
            printf("here's the ring according to printring\n");
            printhalfring(mesh, v1, v2, vertring, ringsize);
        }
        
        /* stats stuff */
        stats.ringsizeattempts[numedgetets[i]]++;
        stats.boundaryedgeremovalattempts++;
        stats.edgeremovalattempts++;
        
        /* now that we know we have a good ring of vertices around this
           edge, we see if by removing the edge we can improve quality.
           to do this, we find the optimal triangulation of the ring
           of vertices around the edge, and see if the tets induced by
           this triangulation are all of better quality than worst tet
           in the original triangulation */
        edgeremoved = removeedge(mesh, v1, v2, vertring, ringsize, minbeforequal, newtets, &newtetcount, minafterqual, true); 
        if (edgeremoved == 1)
        {
            /* stats stuff */
            stats.edgeremovals++;
            stats.boundaryedgeremovals++;
            stats.ringsizesuccess[numedgetets[i]]++;
            
            if (ringsizes != NULL)
            {
                if (numedgetets[i] > *biggestring)
                {
                    *biggestring = numedgetets[i];
                    if (improvebehave.verbosity > 5)
                    {
                        printf("new biggest ring of %d tets\n",*biggestring);
                    }
                }
                /* TODO... fix so count is right! */
                if (numedgetets[i] > 2)
                {
                    ringsizes[numedgetets[i]-3]++;
                }
            }
            
            if (improvebehave.verbosity > 5)
            {
                printf("shit! actually removed a BOUNDARY edge improving quality from %.17g to %.17g, delta of %.17g\n", pq(minbeforequal), pq(*minafterqual),pq(*minafterqual-minbeforequal));
                printf("we started with %d tets, and now have %d\n", numedgetets[i], newtetcount);
                printf("here are the new ones:\n");
                printtets(mesh, newtets, newtetcount);
            }
            
            /* check to make sure all of the new tets are positive orientation, and in the mesh 
               also, if their quality is below our quality threshold, push them on stack */
            for (j=0; j<newtetcount; j++)
            {
                assert(tetexists(mesh, newtets[j][0], newtets[j][1], newtets[j][2], newtets[j][3]) == 1);
                newqual = tetquality(mesh, newtets[j][0], newtets[j][1], newtets[j][2], newtets[j][3], improvebehave.qualmeasure);
                assert(newqual > 0);
                
                if (tetstack != NULL)
                {
                    /* push this tet on the output stack */
                    stacktet = (struct improvetet *) stackpush(tetstack);
                    stacktet->quality = newqual;
                    stacktet->verts[0] = newtets[j][0];
                    stacktet->verts[1] = newtets[j][1];
                    stacktet->verts[2] = newtets[j][2];
                    stacktet->verts[3] = newtets[j][3];
                }
            }
            
            /* don't check the other edges of this tet */
            break;
        }
    }
    
    if (edgeremoved == 1)
    {
        return 1;
    }
    else
    {
        return 0;   
    }
}

/* try edge removal on all 6 edges of the specified tet. if removal
   succeeds, return 1. Otherwise, return 0. */
int tryedgeremove(struct tetcomplex *mesh,
                   tag vtx1,
                   tag vtx2,
                   tag vtx3,
                   tag vtx4,
                   struct arraypoolstack *tetstack,
                   int ringsizes[MAXRINGTETS],
                   int *biggestring,
                   starreal *minafterqual)
{
    tag tet[4];                   /* the current tet we are trying to improve */
    int i,j,k,l,ringi;            /* loop indices for each tet vertex */
    tag tetring[MAXRINGTETS][4];  /* tetrahedra in a ring around the edge */
    tag vertring[MAXRINGTETS];    /* tags of vertices in ring around edge */
    bool boundedge;               /* whether a particular edge is a boundary edge */
    tag bfv[2];                   /* boundary face vertex tags */
    int ringcount = 0;            /* the number of vertices found in the ring so far */
    starreal minbeforequal;       /* the minimum quality of elements in the ring */
    starreal quality;             /* the quality of the current element in the ring */
    int temp;                     /* holding for variable swap */
    int edgeremoved = 0;
    tag newtets[MAXNEWTETS][4];   /* array to hold the new submesh after edge flipping */
    int newtetcount = 0;          /* number of tets in new arrangement */
    starreal newqual;             /* quality of newly generated tets */
    struct improvetet *stacktet;  /* for pushing newly created tets on the stack */
    bool boundaryedgeremoved = false; /* was boundary edge removal successful? */
    
    /* first, check to make sure this tet still exists in the mesh */
    if (tetexists(mesh, vtx1, vtx2, vtx3, vtx4) == 0)
    {
        return 0;
    }
    
    stats.edgeremovalattempts++;
    
    tet[0] = vtx1;
    tet[1] = vtx2;
    tet[2] = vtx3;
    tet[3] = vtx4;
    
    if (improvebehave.boundedgeremoval)
    {
        boundaryedgeremoved = tryboundaryedgeremove(mesh,
                                                vtx1, vtx2, vtx3, vtx4,
                                                tetstack,
                                                ringsizes,
                                                biggestring,
                                                minafterqual);
                                                
        /* if we removed a boundary edge, don't bother with the rest of the edges */
        if (boundaryedgeremoved) return 1;
    }
    
    /* loop over all 6 edges of the tetrahedron */
    for (i = 0; i < 3; i++) 
    {
        /* don't try other edges if previous one has been removed */
        if (edgeremoved == 1)
        {
            break;
        }
        
        for (j = i + 1; j < 4; j++) 
        {
            k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
            l = 6 - i - j - k;
            /* to get right sequence, need to swap k and l sometimes */
            if ((i+j) % 2 == 0)
            {
                temp = k;
                k = l;
                l = temp;
            }
            
            /* fetch the ring of tets around this edge, checking whether the
               edge is on the boundary */
            boundedge = getedgering(mesh, tet[i], tet[j], tet[k], tet[l],
                                    &ringcount, tetring, bfv);
            
            /* if it's a boundary edge, proceed to the next one */
            if (boundedge) continue;
            
            /* stats stuff */
            stats.ringsizeattempts[ringcount]++;
            stats.edgeremovalattempts++;
            
            /* there should be at least three tets in a ring */
            assert(ringcount >= 3); 
            
            /* build ring of vertices from tet list and determine minimum quality */
            minbeforequal = HUGEFLOAT;
            for (ringi=0; ringi < ringcount; ringi++)
            {
                quality = tetquality(mesh, 
                                     tetring[ringi][0], 
                                     tetring[ringi][1], 
                                     tetring[ringi][2], 
                                     tetring[ringi][3],
                                     improvebehave.qualmeasure);
                if (quality < minbeforequal) minbeforequal = quality;
                vertring[ringi] = tetring[ringi][2];
            }
            
            /* now that we know we have a good ring of vertices around this
               edge, we see if by removing the edge we can improve quality.
               to do this, we find the optimal triangulation of the ring
               of vertices around the edge, and see if the tets induced by
               this triangulation are all of better quality than worst tet
               in the original triangulation */
            edgeremoved = removeedge(mesh, tet[i], tet[j], vertring, ringcount, minbeforequal, newtets, &newtetcount, minafterqual, false);
            assert(newtetcount < MAXNEWTETS); 
            if (edgeremoved == 1)
            {
                /* stats stuff */
                stats.edgeremovals++;
                stats.ringsizesuccess[ringcount]++;
                
                if (ringsizes != NULL)
                {
                    if (ringcount > *biggestring)
                    {
                        *biggestring = ringcount;
                        if (improvebehave.verbosity > 5)
                        {
                            printf("new biggest ring of %d tets\n",*biggestring);
                        }
                    }
                    ringsizes[ringcount-3]++;
                }
                
                if (improvebehave.verbosity > 5)
                {
                    printf("shit! actually removed an edge improving quality from %.17g to %.17g, delta of %.17g\n", pq(minbeforequal), pq(*minafterqual),pq(*minafterqual-minbeforequal));
                    printf("we started with %d tets, and now have %d\n", ringcount, newtetcount);
                    printf("here are the new ones:\n");
                    printtetstags(newtets, newtetcount);
                }
                
                /* check to make sure all of the new tets are positive orientation, and in the mesh 
                   also, if their quality is below our quality threshold, push them on stack */
                for (j=0; j<newtetcount; j++)
                {
                    if (tetexists(mesh, newtets[j][0], newtets[j][1], newtets[j][2], newtets[j][3]) != 1)
                    {
                        printf("Missing new tet in output ring of edge removal!\n");
                        printf("j=%d, newtetcount=%d, MAXRINGTETS=%d\n", j, newtetcount, MAXRINGTETS);
                    }
                    assert(tetexists(mesh, newtets[j][0], newtets[j][1], newtets[j][2], newtets[j][3]) == 1);
                    newqual = tetquality(mesh, newtets[j][0], newtets[j][1], newtets[j][2], newtets[j][3], improvebehave.qualmeasure);
                    assert(newqual > 0);
                    
                    if (tetstack != NULL)
                    {
                        /* push this tet on the output stack */
                        /* push this tet on the output stack */
                        if (tetinstack(tetstack,
                                       newtets[j][0],
                                       newtets[j][1],
                                       newtets[j][2],
                                       newtets[j][3]) == false)
                        {
                            stacktet = (struct improvetet *) stackpush(tetstack);
                            stacktet->quality = newqual;
                            stacktet->verts[0] = newtets[j][0];
                            stacktet->verts[1] = newtets[j][1];
                            stacktet->verts[2] = newtets[j][2];
                            stacktet->verts[3] = newtets[j][3];
                        }
                    }
                }
                
                /* don't check the other edges of this tet */
                break;
            }  
        }
    }
    if (edgeremoved == 1)
    {
        return 1;
    }
    else
    {
        return 0;   
    }
}

bool try22flip(struct tetcomplex *mesh,
               tag face[3],
               tag bot,
               tag top,
               int edge[2],
               tag newtets[][4],
               int *numnewtets,
               bool requireimprove)
{
    int other;                    /* the vertex of the face not on the edge being flipped */
    starreal minbefore, minbefore2; /* qualities of original tets */
    starreal minafter, minafter2;   /* qualities of tets after flip */
    tag outin1[2], outin2[2];     /* for testing if these faces are on the boundary */
    bool foundface;
    
    if (improvebehave.anisotropic) return false;
    
    /* stats update */
    stats.flip22attempts++;
    
    /* compute initial minimum quality */
    minbefore = tetquality(mesh, top, face[0], face[1], face[2], improvebehave.qualmeasure);
    minbefore2 = tetquality(mesh, bot, face[2], face[1], face[0], improvebehave.qualmeasure);
    assert(minbefore > 0 && minbefore2 > 0);
    assert(tetexists(mesh, top, face[0], face[1], face[2]));
    assert(tetexists(mesh, bot, face[2], face[1], face[0]));
    
    if (minbefore2 < minbefore) minbefore = minbefore2;
    
    /* figure out the "other" vertex on the face */
    if (edge[0] != 0 && edge[1] != 0)
    {
        other = 0;
    }
    else
    {
        if (edge[0] != 1 && edge[1] != 1)
        {
            other = 1;
        }
        else
        {
            other = 2;
        }
    }
    assert(other != edge[0] && other != edge[1]);
    
    /* make sure the faces in the 2-2 flip are on the boundary */
    foundface = tetcomplexadjacencies(mesh, top, face[edge[0]], face[edge[1]], outin1);
    assert(foundface);
    foundface = tetcomplexadjacencies(mesh, bot, face[edge[1]], face[edge[0]], outin2);
    assert(foundface);
    
    /* check the first face to make sure it's a boundary tet */
    if (outin1[0] != GHOSTVERTEX || outin2[0] != GHOSTVERTEX)
    {
        /* we can't flip these, give up */
        return false;
    }
    
    /* compute quality of tets after the flip */
    minafter = tetquality(mesh, face[other], face[edge[0]], top, bot, improvebehave.qualmeasure);
    minafter2 = tetquality(mesh, face[other], face[edge[1]], bot, top, improvebehave.qualmeasure);
    
    if (!improvebehave.anisotropic)
    {
        assert(minafter >= 0 && minafter2 >= 0);
    }
    
    /* don't allow zero-quality tets to be created */
    if (minafter < MINTETQUALITY || minafter2 < MINTETQUALITY)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("rejecting tet of quality %g or %g\n", pq(minafter), pq(minafter2));
        }
        return false;
    }
    
    if (minafter2 < minafter) minafter = minafter2;
    
    /* if quality is improved, or if we don't care, do the flip */
    if ((minafter > minbefore) || (requireimprove == false))
    {
        flip22(mesh, face[edge[0]], face[edge[1]], face[other], bot, top, true);
        assert(tetexists(mesh, face[other], face[edge[0]], top, bot));
        assert(tetexists(mesh, face[other], face[edge[1]], bot, top));
        assert(tetquality(mesh, face[other], face[edge[0]], top, bot, improvebehave.qualmeasure) > 0);
        assert(tetquality(mesh, face[other], face[edge[1]], bot, top, improvebehave.qualmeasure) > 0);
        
        /* record the new tets */
        *numnewtets = 2;
        newtets[0][0] = face[other];
        newtets[0][1] = face[edge[0]];
        newtets[0][2] = top;
        newtets[0][3] = bot;
        newtets[1][0] = face[other];
        newtets[1][1] = face[edge[1]];
        newtets[1][2] = bot;
        newtets[1][3] = top;
        
        stats.flip22successes++;
        
        return true;
    }
    return false;
}

/* given an edge (1,2) and a pair of "sandwich" vertices a and b,
   (a above) determine what the neighbor across the edge is.
   if there is none, return GHOSTVERTEX */
tag sandwichneighbor(struct tetcomplex *mesh,
                       tag v1,
                       tag v2,
                       tag a,
                       tag b)
{
    tag anextprev[2]; /* the next and previous vertices from the face (1,2,a) */
    tag bnextprev[2]; /* the next and previous vertices from the face (2,1,b) */
    int foundface;    /* whether a particular face was found */
    
    /* retrieve adjacency info */
    foundface = tetcomplexadjacencies(mesh, v1, v2, a, anextprev);
    assert(foundface == 1);
    foundface = tetcomplexadjacencies(mesh, v2, v1, b, bnextprev);
    assert(foundface == 1);
    
    /* check that the "ancestor" tets exist */
    assert(tetexists(mesh, anextprev[1], v2, v1, a));
    assert(tetexists(mesh, bnextprev[1], v1, v2, b));
    
    /* if the next vertex for both faces is the same, then we've got a sandwich neighbor */
    if (anextprev[0] == bnextprev[0])
    {
        return anextprev[0];
    }
    /* otherwise, no neighbor here */
    return GHOSTVERTEX;
}

/* structure to hold a face, g, and pointers to it's two children */
struct facechildren
{
    tag face[3];
    int child1;
    int child2;
};
#define NOCHILD -1

void printfacetree(struct tetcomplex *mesh,
                   struct facechildren tree[],
                   int treesize)
{
    int i;
    printf("Here is the current face tree of %d faces:\n", treesize);
    
    for (i=0; i<treesize; i++)
    {
        printf("Face %d: (%d %d %d), children %d and %d\n", i, (int) tree[i].face[0], (int) tree[i].face[1], (int) tree[i].face[2], tree[i].child1, tree[i].child2);
    }
}

/* given a face f, an edge uw of that face, and two sandwiching vertices a and b,
   determine if when removing f whether also removing it's neighbor across uw, g,
   would be beneficial. if so, return true. otherwise, return false */
bool testneighbor(struct tetcomplex *mesh,
                  struct facechildren facetree[],
                  int *treesize,
                  tag a,
                  tag b,
                  tag u,
                  tag w,
                  starreal *qold,
                  starreal *qnew,
                  int *g)
{
    starreal quw, qauvw, quvwb;
    starreal ouv, ovw, nuv, nvw;
    int huv;
    int hvw;
    bool uvneighbor, vwneighbor;
    starreal *avtx;
    starreal *bvtx;
    starreal *uvtx;
    starreal *vvtx;
    starreal *wvtx;
    starreal juv, jvw, jwu;
    tag v;
    
    if (improvebehave.verbosity > 5)
    {
        printf("In testneighbor. a=%d, b=%d, u=%d, v=%d\n", (int) a, (int) b, (int) u, (int) w);
    }
    
    /* the quality of this individual tet in the new ring */
    quw = tetquality(mesh, a, b, u, w, improvebehave.qualmeasure);
    
    /* set worst-case return values */
    *g = NOCHILD;
    *qold = HUGEFLOAT;
    *qnew = quw;
    
    /* check if f has a neighbor face across uw */
    v = sandwichneighbor(mesh, u, w, a, b);
    
    /* if not, we certainly can't remove this neighbor */
    if (v == GHOSTVERTEX)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("no neighbor across (%d %d)\n", (int) u, (int) w);
        }
        return false;
    }
    
    /* use orientation tests to confirm that none of the vertices
       u, v, or w lie inside conv({a,b,u,v,w}) */
    avtx = ((struct vertex *) tetcomplextag2vertex(mesh, a))->coord;
    bvtx = ((struct vertex *) tetcomplextag2vertex(mesh, b))->coord;
    uvtx = ((struct vertex *) tetcomplextag2vertex(mesh, u))->coord;
    vvtx = ((struct vertex *) tetcomplextag2vertex(mesh, v))->coord;
    wvtx = ((struct vertex *) tetcomplextag2vertex(mesh, w))->coord;
    juv = orient3d(&behave, avtx, bvtx, uvtx, vvtx);
    jvw = orient3d(&behave, avtx, bvtx, vvtx, wvtx);
    jwu = orient3d(&behave, avtx, bvtx, wvtx, uvtx);
    
    if (((juv > 0) && (jvw > 0)) ||
        ((jvw > 0) && (jwu > 0)) ||
        ((jwu > 0) && (juv > 0)))
    {
        if (improvebehave.verbosity > 5)
        {
            printf("found workable neighbor %d across edge (%d %d)\n", (int) v, (int) u, (int) w);
        }
    }
    else
    {
        if (improvebehave.verbosity > 5)
        {
            printf("can't add face (%d %d %d) to the tree because there's no positively-oriented edges\n", (int) u, (int) v, (int) w);
        }
        return false;
    }
    
    /* now test the two potential children of this face */
    uvneighbor = testneighbor(mesh, facetree, treesize, a, b, u, v, &ouv, &nuv, &huv);
    vwneighbor = testneighbor(mesh, facetree, treesize, a, b, v, w, &ovw, &nvw, &hvw);
    
    /* compute potential qualities */
    qauvw = tetquality(mesh, a, u, v, w, improvebehave.qualmeasure);
    quvwb = tetquality(mesh, u, v, w, b, improvebehave.qualmeasure);
    
    /* qold = min(qauvw, quvwb, ouv, ovw) */
    if (uvneighbor) *qold = ouv;
    if (vwneighbor && (ovw < *qold)) *qold = ovw;
    if (ouv < *qold) *qold = ouv;
    if (ovw < *qold) *qold = ovw;
    
    /* qnew = min(nuv, nvw) */
    *qnew = nuv;
    if (nvw < *qnew) *qnew = nvw;
    
    /* should g be removed if f is ? */
    if ((*qnew > *qold) || (*qnew > quw))
    {
        
        /* yes! add g and g's children to the face tree */
        /* record the vertices of the new face g = (u,v,w),
           whose verts are counterclockwise from a's point of view. */
        *g = (*treesize)++;
        facetree[*g].face[0] = u;
        facetree[*g].face[1] = v;
        facetree[*g].face[2] = w;
        facetree[*g].child1 = huv;
        facetree[*g].child2 = hvw;
        
        return true;
    }
    
    /* g shouldn't be removed, return NOCHILD */
    return false;
}

/* remove face g and, recursively, it's children */
void flip32recurse(struct tetcomplex *mesh,
                   struct facechildren tree[],
                   int treesize,
                   int g,
                   tag a,
                   tag b,
                   tag newtets[][4],
                   int *numnewtets)
{
    tag u, v, w;
    
    /* fetch face g from the tree */
    u = tree[g].face[0];
    v = tree[g].face[1];
    w = tree[g].face[2];
    
    if (improvebehave.verbosity > 5)
    {
        printf("about to do a 3-2 flip on submesh a=%d b=%d u=%d v=%d w=%d\n", (int) a, (int) b, (int) u, (int) v, (int) w);
    }
    
    /* check that the old tets exist */
    assert(tetexists(mesh, a, u, v, w));
    assert(tetexists(mesh, u, v, w, b));
    assert(tetexists(mesh, a, b, u, w));
    
    if (improvebehave.verbosity > 5)
    {
        printf("Here's the submesh before the flip\n");
        printf("{");
        printtetvertssep(mesh, a, u, v, w);
        printf(";\n");
        printtetvertssep(mesh, u, v, w, b);
        printf(";\n");
        printtetvertssep(mesh, a, b, u, w);
        printf("};");
    }
    
    /* remove g with a 3-2 flip */
    flip32(mesh, a, b, v, w, u, true);
    
    /* check that the new tets exist */
    assert(tetexists(mesh, a, b, u, v));
    assert(tetexists(mesh, a, b, v, w));
    
    /* remove children, if any */
    if (tree[g].child1 != NOCHILD)
    {
        flip32recurse(mesh, tree, treesize, tree[g].child1, a, b, newtets, numnewtets);
    }
    else
    /* this is a permanent tet */
    {
        newtets[*numnewtets][0] = a;
        newtets[*numnewtets][1] = b;
        newtets[*numnewtets][2] = u;
        newtets[*numnewtets][3] = v;
        (*numnewtets)++;
    }
    if (tree[g].child2 != NOCHILD)
    {
        flip32recurse(mesh, tree, treesize, tree[g].child2, a, b, newtets, numnewtets);
    }
    else
    /* this is a permanent tet */
    {
        newtets[*numnewtets][0] = a;
        newtets[*numnewtets][1] = b;
        newtets[*numnewtets][2] = v;
        newtets[*numnewtets][3] = w;
        (*numnewtets)++;
    }
}

/* f (u, v, w) is a triangular face under consideration for removal. all faces
   sandwiched between the same two vertices (a and b) as f are considered
   for removal */
bool removemultiface(struct tetcomplex *mesh,
                     tag u,
                     tag v,
                     tag w,
                     int *numfaces,
                     tag newtets[][4],
                     int *numnewtets)
{
    struct facechildren facetree[MAXFACETREESIZE]; /* holds tree of faces to be removed */
    int treesize = 0;
    tag a, b;
    tag abovebelow[2];
    int foundface;
    starreal qnew, qold;
    starreal ouv, ovw, owu, nuv, nvw, nwu, qauvw, quvwb;
    int guv, gvw, gwu;
    int i;
    starreal *vtx1;
    starreal *vtx2;
    starreal *vtx3;
    starreal *vtxa;
    starreal *vtxb;
    starreal *vtxu;
    starreal *vtxv;
    starreal *vtxw;
    bool foundabface = false;
    starreal juv, jvw, jwu;
    
    *numnewtets = 0;
    
    if (improvebehave.verbosity > 5)
    {
        printf("\n\nAttempting multi-face removal on face (%d %d %d)\n", (int) u, (int) v, (int) w);
    }
    
    /* figure out what a and b are with an adjacency query */
    foundface = tetcomplexadjacencies(mesh, u, v, w, abovebelow);
    assert(foundface == 1);
    a = abovebelow[0];
    b = abovebelow[1];
    
    /* if either of the vertices are not there, bail */
    if (a == GHOSTVERTEX || b == GHOSTVERTEX)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("multi-face removal failed because this is a boundary face.\n");
        }
        return false;
    }
    
    vtxa = ((struct vertex *) tetcomplextag2vertex(mesh, a))->coord;
    vtxb = ((struct vertex *) tetcomplextag2vertex(mesh, b))->coord;
    vtxu = ((struct vertex *) tetcomplextag2vertex(mesh, u))->coord;
    vtxv = ((struct vertex *) tetcomplextag2vertex(mesh, v))->coord;
    vtxw = ((struct vertex *) tetcomplextag2vertex(mesh, w))->coord;
    
    /* make sure we don't have two reflex edges on this face with respect to (a,b) */
    juv = orient3d(&behave, vtxa, vtxb, vtxu, vtxv);
    jvw = orient3d(&behave, vtxa, vtxb, vtxv, vtxw);
    jwu = orient3d(&behave, vtxa, vtxb, vtxw, vtxu);
    
    if (((juv > 0) && (jvw > 0)) ||
        ((jvw > 0) && (jwu > 0)) ||
        ((jwu > 0) && (juv > 0)))
    {
        ;
    }
    else
    {
        if (improvebehave.verbosity > 5)
        {
            printf("can't even get started with this face, two reflex edges\n");
        }
        return false;
    }
    
    /* figure out what neighbors might also be removed */
    testneighbor(mesh, facetree, &treesize, a, b, u, v, &ouv, &nuv, &guv);
    testneighbor(mesh, facetree, &treesize, a, b, v, w, &ovw, &nvw, &gvw);
    testneighbor(mesh, facetree, &treesize, a, b, w, u, &owu, &nwu, &gwu);
    
    /* calculate potential qualities */
    qauvw = tetquality(mesh, a, u, v, w, improvebehave.qualmeasure);
    quvwb = tetquality(mesh, u, v, w, b, improvebehave.qualmeasure);
    
    /* qold = min(qauvw, quvwb, ouv, ovw, owu) */
    qold = qauvw;
    if (quvwb < qold) qold = quvwb;
    if (ouv < qold) qold = ouv;
    if (ovw < qold) qold = ovw;
    if (owu < qold) qold = owu;
    
    /* qnew = min(nuv, nvw, nwu) */
    qnew = nuv;
    if (nvw < qnew) qnew = nvw;
    if (nwu < qnew) qnew = nwu;
    
    /* save stats */
    stats.facesizeattempts[treesize+1]++;
    
    /* is the face removal worth it? */
    if (qnew <= qold)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("multi-face removal failed because quality didn't improve\n");
        }
        return false;
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("woot, old qual = %g, new qual = %g\n", pq(qold), pq(qnew));
    }
    
    /* now, make sure that one of the faces in our tree is the one
       that is pierced by ab */
    /* first check the face itself */
    if ( (orient3d(&behave, vtxa, vtxb, vtxu, vtxv) > 0) &&
         (orient3d(&behave, vtxa, vtxb, vtxv, vtxw) > 0) &&
         (orient3d(&behave, vtxa, vtxb, vtxw, vtxu) > 0))
    {
        foundabface = true;
    }
    else
    /* now look in the tree */
    {
        for (i=0; i<treesize; i++)
        {
            vtx1 = ((struct vertex *) tetcomplextag2vertex(mesh, facetree[i].face[0]))->coord;
            vtx2 = ((struct vertex *) tetcomplextag2vertex(mesh, facetree[i].face[1]))->coord;
            vtx3 = ((struct vertex *) tetcomplextag2vertex(mesh, facetree[i].face[2]))->coord;
        
            /* check if ab is on the positive side of each edge */
            if (orient3d(&behave, vtxa, vtxb, vtx1, vtx2) < 0) continue;
            if (orient3d(&behave, vtxa, vtxb, vtx2, vtx3) < 0) continue;
            if (orient3d(&behave, vtxa, vtxb, vtx3, vtx1) < 0) continue;
        
            /* this face is pierced by ab! sweet. */
            foundabface = true;
            break;
        }
    }
    
    if (foundabface == false)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("Can't do face removal because the face pierced by ab wasn't in tree\n");
            for (i=0; i<treesize; i++)
            {
                printtetvertssep(mesh, a, facetree[i].face[0], facetree[i].face[1], facetree[i].face[2]);
                printf(";\n");
                printtetvertssep(mesh, b, facetree[i].face[2], facetree[i].face[1], facetree[i].face[0]);
                printf(";\n");
            }
            printf("};\n");
        }
        
        return false;
    }
    
    /* remove f and the rest of the faces that are beneficial */
    if (improvebehave.verbosity > 5)
    {
        printf("Yay! we can remove this group of faces. Here are all the tets in the tree:\n");
        printf("{\n");
        for (i=0; i<treesize; i++)
        {
            printtetvertssep(mesh, a, facetree[i].face[0], facetree[i].face[1], facetree[i].face[2]);
            printf(";\n");
            printtetvertssep(mesh, b, facetree[i].face[2], facetree[i].face[1], facetree[i].face[0]);
            printf(";\n");
        }
        printf("};\n");
    }
    
    /* start by removing f with a single 2-3 flip */
    flip23(mesh, u, v, w, b, a, true);
    /* make sure new tets exist */
    assert(tetexists(mesh, a, b, u, v));
    assert(tetexists(mesh, a, b, v, w));
    assert(tetexists(mesh, a, b, w, u));
    
    /* remove children (and their children) */
    if (guv != NOCHILD) 
    {
        flip32recurse(mesh, facetree, treesize, guv, a, b, newtets, numnewtets);
    }
    else
    /* this is a permanent tet */
    {
        newtets[*numnewtets][0] = a;
        newtets[*numnewtets][1] = b;
        newtets[*numnewtets][2] = u;
        newtets[*numnewtets][3] = v;
        (*numnewtets)++;
    }
    if (gvw != NOCHILD) 
    {
        flip32recurse(mesh, facetree, treesize, gvw, a, b, newtets, numnewtets);
    }
    else
    /* this is a permanent tet */
    {
        newtets[*numnewtets][0] = a;
        newtets[*numnewtets][1] = b;
        newtets[*numnewtets][2] = v;
        newtets[*numnewtets][3] = w;
        (*numnewtets)++;
    }
    if (gwu != NOCHILD)
    {
        flip32recurse(mesh, facetree, treesize, gwu, a, b, newtets, numnewtets);
    }
    else
    /* this is a permanent tet */
    {
        newtets[*numnewtets][0] = a;
        newtets[*numnewtets][1] = b;
        newtets[*numnewtets][2] = w;
        newtets[*numnewtets][3] = u;
        (*numnewtets)++;
    }
    
    *numfaces = treesize + 1;
    
    if (improvebehave.verbosity > 5)
    {
        printf("successfully removed %d faces\n", *numfaces);
    }
    
    /* save stats */
    stats.facesizesuccess[treesize+1]++;
    
    return true;
}

#define FLIP23SUCCESS 1
#define FLIP22SUCCESS 2
#define MULTIFACESUCCESS 3

/* attempt a 2-3 flip to remove the face vtx1, vtx2, vtx3. it can be
   required or not that this flip improve the quality of the submesh.
   TODO is this function really necessary? Need to clean up edge removal in general... */
int try23flipold(struct tetcomplex *mesh,
               tag vtx1,
               tag vtx2,
               tag vtx3,
               tag newtets[][4],
               int *numnewtets,
               bool requireimprove)
{
    tag topbot[2]; /* the adjacencies of this face */
    starreal minbeforequal;  /* qualities of tets before the flip */
    starreal minbeforequal2;
    starreal minafterqual;   /* qualities of tets after the flip */
    starreal qual12, qual23, qual31;
    int foundface;
    int numcoplanar;
    int coplanaredges[2][2];
    tag face22[3];
    bool success;
    int numreflex;
    
    face22[0] = vtx1;
    face22[1] = vtx2;
    face22[2] = vtx3;
    
    /* get the top/bottom vertices for the flip */
    foundface = tetcomplexadjacencies(mesh, 
                                      vtx1,
                                      vtx2,
                                      vtx3,
                                      topbot);
    
    /* this face had better exist in the mesh */
    assert(foundface == 1);
    
    /* check to make sure this edge has no reflex edges */
    numreflex = countreflex(mesh, vtx1, vtx2, vtx3, &numcoplanar, coplanaredges);
    
    if (numreflex == 0)
    {
        if (numcoplanar != 0)
        {
            /* try a flip of each of the edges that adjoin
               a pair of coplanar faces */
            if (numcoplanar == 1)
            {
                success = try22flip(mesh, face22, topbot[1], topbot[0], coplanaredges[0], newtets, numnewtets, requireimprove);
                if (success)
                {
                    return FLIP22SUCCESS;
                }
            }
            return false;
        }
        /* only faces with no reflex edges are eligible for 2-3 flips */
        else
        {
            /* compute the quality of the other tets involved in the flip,
               with vertices before the flip, remember the worst */
            minbeforequal = tetquality(mesh, 
                                       topbot[0], 
                                       vtx1,
                                       vtx2,
                                       vtx3,
                                       improvebehave.qualmeasure);
            minbeforequal2 = tetquality(mesh, 
                                        topbot[1], 
                                        vtx3,
                                        vtx2,
                                        vtx1,
                                        improvebehave.qualmeasure);                           
            if (minbeforequal2 < minbeforequal)
            {
                minbeforequal = minbeforequal2;
            }
            
            /* the three tets that would exist after the flip are:
               (top, 1, 2, bot)
               (top, 2, 3, bot)
               (top, 3, 1, bot)
            */
            qual12 = tetquality(mesh, topbot[0], vtx1, vtx2, topbot[1], improvebehave.qualmeasure);
            qual23 = tetquality(mesh, topbot[0], vtx2, vtx3, topbot[1], improvebehave.qualmeasure);
            qual31 = tetquality(mesh, topbot[0], vtx3, vtx1, topbot[1], improvebehave.qualmeasure);
            
            if (qual12 < MINTETQUALITY || qual23 < MINTETQUALITY || qual31 < MINTETQUALITY)
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("In 2-3 flip, rejecting tet of qual %g %g %g\n", pq(qual12), pq(qual23), pq(qual31));
                }
                return false;
            }
            
            /* these should all still be positive-orientation tets */
            assert(qual12 > 0 && qual23 > 0 && qual31 > 0);
            
            minafterqual = qual12;
            if (qual23 < minafterqual)
            {
                minafterqual = qual23;
            }
            if (qual31 < minafterqual)
            {
                minafterqual = qual31;
            }
            
            /* if minimum quality is improved or we don't care, do the flip */
            if ((minbeforequal < minafterqual) || (requireimprove == false))
            {
                /* actually perform the 2-3 flip */
                /* tetcomplex23flip(mesh, tet[j], tet[k], tet[l], topbot[1], topbot[0]); */
                /* use my flip for now TODO: switch back to Jonathan's flip after bug fix */
                flip23(mesh, vtx1, vtx2, vtx3, topbot[1], topbot[0], true);
            
                /* each of these new tets should exist in the mesh now */
                assert(tetexists(mesh, topbot[0], vtx1, vtx2, topbot[1]));
                assert(tetexists(mesh, topbot[0], vtx2, vtx3, topbot[1]));
                assert(tetexists(mesh, topbot[0], vtx3, vtx1, topbot[1]));
                
                /* record identity of new tets */
                *numnewtets = 3;
                newtets[0][0] = topbot[0];
                newtets[0][1] = vtx1;
                newtets[0][2] = vtx2;
                newtets[0][3] = topbot[1];
                newtets[1][0] = topbot[0];
                newtets[1][1] = vtx2;
                newtets[1][2] = vtx3;
                newtets[1][3] = topbot[1];
                newtets[2][0] = topbot[0];
                newtets[2][1] = vtx3;
                newtets[2][2] = vtx1;
                newtets[2][3] = topbot[1];
                
                return FLIP23SUCCESS;
            }
        }
    }
    return false;
}

/* attempt to remove the face (1,2,3). If it has coplanar boundary faces,
   use a 2-2 flip where appropriate. Otherwise, use multi-face removal.
   If a quality-insensitive flip is desired, for now use the old 2-3 single
   flip */
int tryfaceremove(struct tetcomplex *mesh,
               tag vtx1,
               tag vtx2,
               tag vtx3,
               int *numfaces,
               tag newtets[][4],
               int *numnewtets,
               bool requireimprove)
{
    tag topbot[2]; /* the adjacencies of this face */
    int foundface;
    int numcoplanar;
    int coplanaredges[2][2];
    tag face22[3];
    bool success;
    int numreflex;
    
    face22[0] = vtx1;
    face22[1] = vtx2;
    face22[2] = vtx3;
    
    /* get the top/bottom vertices for the flip */
    foundface = tetcomplexadjacencies(mesh, 
                                      vtx1,
                                      vtx2,
                                      vtx3,
                                      topbot);
    
    /* this face had better exist in the mesh */
    if (foundface == false)
    {
        return false;
    }
    
    stats.faceremovalattempts++;
    
    /* check to make sure this face has no reflex edges */
    numreflex = countreflex(mesh, vtx1, vtx2, vtx3, &numcoplanar, coplanaredges);
    
    if (numreflex == 0)
    {
        if (numcoplanar != 0)
        {
            /* try a flip of each of the edges that adjoin
               a pair of coplanar faces */
            if (numcoplanar == 1 && improvebehave.flip22 == 1 && !improvebehave.anisotropic)
            {
                stats.facesizeattempts[1]++;
                success = try22flip(mesh, face22, topbot[1], topbot[0], coplanaredges[0], newtets, numnewtets, requireimprove);
                
                if (success)
                {
                    *numfaces = 1;
                    stats.facesizesuccess[1]++;
                    stats.faceremovals++;
                    return FLIP22SUCCESS;
                }
            }
            return false;
        }
        /* only faces with no reflex edges are eligible for 2-3 flips */
        else
        {
            /* if single face removal is enabled */
            if (improvebehave.singlefaceremoval == 1)
            {
                /* if we want quality-insensitive flip, use old 2-3 flip for now */
                if (requireimprove == false)
                {
                    success = try23flipold(mesh, vtx1, vtx2, vtx3, newtets, numnewtets, requireimprove);
                    if (success) return FLIP23SUCCESS;
                }
                /* if we aren't allowed to do multi-face flips, use old 2-3 flip */
                if (improvebehave.multifaceremoval == 0)
                {
                    stats.facesizeattempts[1]++;
                    success = try23flipold(mesh, vtx1, vtx2, vtx3, newtets, numnewtets, requireimprove);
                    if (success)
                    {
                        stats.facesizesuccess[1]++;
                        stats.faceremovals++;
                        return FLIP23SUCCESS;
                    }
                }
            }
        }
    }
    
    /* attempt multi-face removal, if it is enabled */
    if (improvebehave.multifaceremoval)
    {
        success = removemultiface(mesh, vtx1, vtx2, vtx3, numfaces, newtets, numnewtets);
        if (success)
        {
            stats.faceremovals++;
            return MULTIFACESUCCESS;
        }
    }
    
    return false;
}

/* try a 2-3 flip on all four faces of the specified tet
   returns 1 if a flip was performed, 0 otherwise */
int tryremoveallfaces(struct tetcomplex *mesh,
                      tag vtx1,
                      tag vtx2,
                      tag vtx3,
                      tag vtx4,
                      struct arraypoolstack *tetstack,
                      int facesizes[],
                      int *biggestsize,
                      starreal *outqual,
                      bool requireimprove)
{
    tag tet[4];          /* the current tet we are trying to improve */
    int i,j,k,l,m;       /* loop indices for tet vertices */
    int numflipped=0;    /* did the flip succeed? */
    int result;
    tag topbot[2];
    int numfaces;
    int numnewtets;
    tag newtets[MAXRINGTETS][4];
    starreal newqual;
    struct improvetet *stacktet;  /* for pushing newly created tets on the stack */
    
    *outqual = 1.0;
    
    /* first, check to make sure this tet still exists in the mesh */
    if (tetexists(mesh, vtx1, vtx2, vtx3, vtx4) == 0)
    {
        return 0;
    }
    
    tet[0] = vtx1;
    tet[1] = vtx2;
    tet[2] = vtx3;
    tet[3] = vtx4;
    
    /* check each of this tet's four faces to see if it is eligible for 2-3 flip */
    /* this loop will loop through faces (j,k,l) oriented toward the interior of the tet 
       (node i), from the perspective of the RHR (curl fingers around face vertices, thumb
       points to the interior of the tet). */
    for (i = 0; i < 4; i++) 
    {
        j = (i + 1) & 3;
        if ((i & 1) != 0)
        {
            k = (i + 3) & 3;
            l = (i + 2) & 3;
        } 
        else
        {
            k = (i + 2) & 3;
            l = (i + 3) & 3;
        }
        
        numfaces = 1;
        
        /* check to make sure this face still exists (i.e., hasn't been erased
           in an earlier 2-2 flip) */
        if (tetcomplexadjacencies(mesh, tet[j], tet[k], tet[l], topbot) == 0)
        {
            continue;
        }
        
        /* if we want to be quality insensitive, do an old-school flip */
        if (requireimprove == false)
        {
            result = try23flipold(mesh, tet[j], tet[k], tet[l], newtets, &numnewtets, false);
        }
        else
        {
            /* try to remove this face */
            result = tryfaceremove(mesh, tet[j], tet[k], tet[l], &numfaces, newtets, &numnewtets, requireimprove);
        }
        if (result) numflipped++;
        
        /* if we're keeping statistics, remember how many faces were removed */
        if (facesizes != NULL)
        {
            if (result == FLIP22SUCCESS)
            {
                facesizes[0]++;
            }
            
            if (result == MULTIFACESUCCESS)
            {
                facesizes[numfaces]++;
                if (numfaces > *biggestsize) *biggestsize = numfaces;
            }
        }
        
        /* if we changed some stuff, add it to the output stack */
        if (result)
        {
            for (m=0; m<numnewtets; m++)
            {
                assert(tetexists(mesh, newtets[m][0], newtets[m][1], newtets[m][2], newtets[m][3]) == 1);
                newqual = tetquality(mesh, newtets[m][0], newtets[m][1], newtets[m][2], newtets[m][3], improvebehave.qualmeasure);
                assert(newqual > 0);
                
                if (newqual < *outqual) *outqual = newqual;
                
                if (tetstack != NULL)
                {
                    if (tetinstack(tetstack,
                                   newtets[m][0],
                                   newtets[m][1],
                                   newtets[m][2],
                                   newtets[m][3]) == false)
                    {
                        /* push this tet on the output stack */
                        stacktet = (struct improvetet *) stackpush(tetstack);
                        stacktet->quality = newqual;
                        stacktet->verts[0] = newtets[m][0];
                        stacktet->verts[1] = newtets[m][1];
                        stacktet->verts[2] = newtets[m][2];
                        stacktet->verts[3] = newtets[m][3];
                    }
                }
            }
        }
    }
    
    return numflipped;
}

/* perform a pass of topological improvement.
   for now, this means trying to remove each edge
   of each tet in the stack that is passed in,
   and if no edge can be removed, trying to remove
   each face. */
bool topopass(struct tetcomplex *mesh,
              struct arraypoolstack *tetstack,
              struct arraypoolstack *outstack,
              int qualmeasure,
              starreal bestmeans[],
              starreal meanqualafter[],
              starreal *minqualafter,
              bool quiet)
{
    starreal outquality;           /* the quality of the current tet */
    struct improvetet *stacktet;   /* point to stack tet */
    struct improvetet *outtet;     /* point to stack tet */
    int removed, flipped;          /* was edge / face removal successful */
    int numremoved = 0;            /* number of edges removed */
    int numflipped = 0;            /* number of 2-3 face flips */
    int ringsizes[MAXRINGTETS];    /* histogram of size of rings of tets */
    int biggestring = 0;           /* biggest ring seen */
    int facesizes[MAXFACETREESIZE];/* histogram of face group sizes */
    int biggestface = 0;
    int i;                         /* loop index */
    int origstacksize;             /* number of tets in the original stack */
    int beforeid = lastjournalentry();
    struct arraypoolstack savestack;     /* save the input stack in case of failure */
    starreal minqualbefore, meanqualbefore[NUMMEANTHRESHOLDS];
    starreal minnow;
    bool dynfailcondition = true;
    
    *minqualafter = HUGEFLOAT;
    
    origstacksize = tetstack->top + 1;
    
    if (improvebehave.verbosity > 5 && outstack != NULL)
    {
        printf("here's the input stack:\n");
        printstack(mesh, tetstack);
    }
    /* compute worst input quality. do it global if no output stack */
    if (outstack != NULL)
    {
        stackquality(mesh, tetstack, qualmeasure, meanqualbefore, &minqualbefore);
    }
    else
    {
        meshquality(mesh, qualmeasure, meanqualbefore, &minqualbefore);
    }
    
    /* initialize ring sizes */
    for (i=0; i<MAXRINGTETS; i++)
    {
        ringsizes[i] = 0;
    }
    
    for (i=0; i<MAXFACETREESIZE; i++)
    {
        facesizes[i] = 0;
    }
    
    /* reset output stack */
    if (outstack != NULL)
    {
        stackrestart(outstack);
        /* save a copy of the input stack */
        stackinit(&savestack, sizeof(struct improvetet));
        copystack(tetstack, &savestack);
    }
    
    /* if we aren't allowed to do any topo stuff, don't even bother */
    if (improvebehave.edgeremoval == 0 &&
        improvebehave.singlefaceremoval == 0 &&
        improvebehave.multifaceremoval == 0)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("Not bothering with topo pass, no topo features enabled\n");
        }
        *minqualafter = minqualbefore;
        if (outstack != NULL)
        {
            stackdeinit(outstack);
            memcpy(outstack, &savestack, sizeof(struct arraypoolstack));
            /* make sure the outquality of the saved stack is same as incoming qual */
            assert(worststackquality(mesh, outstack, qualmeasure) == minqualbefore);
        }
        return false;
    }
    
    /* go through each tet on the stack */
    while (tetstack->top != STACKEMPTY)
    {
        /* pull the top tet off the stack */
        stacktet = (struct improvetet *) stackpop(tetstack);
        
        if (improvebehave.edgeremoval)
        {
            /* try edge removal first */
            removed = tryedgeremove(mesh, 
                      stacktet->verts[0], 
                      stacktet->verts[1], 
                      stacktet->verts[2], 
                      stacktet->verts[3], 
                      outstack,
                      ringsizes,
                      &biggestring,
                      &outquality);
        }
        else
        {
            removed = 0;
        }
        
        /* if edge removal failed, try face removal */
        if (removed == 0)
        {
            /* now try multi-face removal */
            flipped = tryremoveallfaces(mesh, 
                  stacktet->verts[0], 
                  stacktet->verts[1], 
                  stacktet->verts[2], 
                  stacktet->verts[3], 
                  outstack,
                  facesizes,
                  &biggestface,
                  &outquality,
                  true);
        }
        else
        {
            flipped = 0;
        }
        
        /* record what happened */
        if (removed == 1)
        {   
            numremoved++;

            if (numremoved % 1000 == 0 && improvebehave.verbosity > 4 && quiet == false)
            {
                printf("removed %d edges. stack currently has %ld tets.\n",numremoved, tetstack->top);
            }
        }
        
        if (flipped > 0)
        {
            numflipped += flipped;
        }
        
        /* if nothing was done to this tet, push it on the output stack */
        if (removed == 0 && flipped == 0 && outstack != NULL)
        {
            /* push this tet on the output stack */
            if (tetinstack(outstack,
                           stacktet->verts[0],
                           stacktet->verts[1],
                           stacktet->verts[2],
                           stacktet->verts[3]) == false)
            {
                outtet = (struct improvetet *) stackpush(outstack);
                outtet->quality = stacktet->quality;
                outtet->verts[0] = stacktet->verts[0];
                outtet->verts[1] = stacktet->verts[1];
                outtet->verts[2] = stacktet->verts[2];
                outtet->verts[3] = stacktet->verts[3];
            }
        }
        
        removed = 0;
        flipped = 0;
    }
    
    if (outstack != NULL)
    {
        if (improvebehave.verbosity > 4 && quiet == false)
        {
            /*
            printf("here's the output stack:\n");
            printstack(mesh, outstack);
            */
            printf("just completed topological improvment pass.\n");
            printf("    input stack had %d tets\n", origstacksize);
            printf("    output stack had %lu tets\n", outstack->top+1);
            printf("    number of edge/face removals is %d/%d\n", numremoved, numflipped);
            printf("    claimed input quality is            %g\n", pq(minqualbefore));
            printf("    worst quality in the output stack is %g\n", pq(worststackquality(mesh, outstack, qualmeasure)));
        }
        stackquality(mesh, outstack, qualmeasure, meanqualafter, minqualafter);
        
        /* check for success for local dynamic improvement */
        if (improvebehave.dynimprove && quiet == false)
        {
            if (localmeanimprove(meanqualbefore, meanqualafter, 0.001) && *minqualafter >= minqualbefore)
            {
                dynfailcondition = false;
            }
        }
        
        /* if we didn't improve, undo this pass and indicate failure */
        if ((*minqualafter < minqualbefore || (numremoved == 0 && numflipped == 0)) && dynfailcondition)
        {
            invertjournalupto(mesh, beforeid);
            /* send back the saved copy of the input stack as the output stack */
            stackdeinit(outstack);
            memcpy(outstack, &savestack, sizeof(struct arraypoolstack));
            /* make sure the outquality of the saved stack is same as incoming qual */
            stackquality(mesh, outstack, qualmeasure, meanqualbefore, &minnow);
            if (minnow != minqualbefore)
            {
                printf("worststackquality = %g, minqualbefore = %g, diff = %g", pq(minnow), pq(minqualbefore), pq(minnow - minqualbefore));
            }
            assert(minnow == minqualbefore);
            *minqualafter = minqualbefore;
            return false;
        }
        
        stackdeinit(&savestack);
        return true;
        
        /*
        *minqualafter = worstquality(mesh, qualmeasure);
        */
    }
    else
    {
        /* what's the worst quality element in the mesh now? */
        meshquality(mesh, qualmeasure, meanqualafter, minqualafter);
    }
    
    if (improvebehave.verbosity > 3 && quiet == false)
    {
        printf("Completed topological improvment pass on stack of %d tets\n", origstacksize);
        if (improvebehave.verbosity > 5)
        {
            printf("    Best previous means:\n");
            printmeans(bestmeans);
            printf("    Mean qualities after:\n");
            printmeans(meanqualafter);
        }
        printf("    Worst quality before: %g\n", pq(minqualbefore));
        if (minqualbefore < *minqualafter)
        {
            textcolor(BRIGHT, GREEN, BLACK);
        }
        printf("    Worst quality after:  %g\n", pq(*minqualafter));
        textcolor(RESET, WHITE, BLACK);
        if (improvebehave.verbosity > 4)
        {
            printf("    Edges removed: %d\n", numremoved);
            printf("    Ring size histogram:\n");
            for (i=0; i<biggestring-2; i++)
            {
                printf("    [%d]: %d\n",i+3,ringsizes[i]);
            }
            printf("    Face removals: %d\n", numflipped);
            printf("      2-2 flips: %d\n", facesizes[0]);
            for (i=1; i<=biggestface; i++)
            {
                printf("    [%d]: %d\n",i,facesizes[i]);
            }
        }
        assert(*minqualafter >= minqualbefore);
    }
    
    if (outstack != NULL)
    {
        stackdeinit(&savestack);
    }
    
    return true;
}

/* for each tet in the stack, try to contract its edges */
bool contractpass(struct tetcomplex *mesh,
                  struct arraypoolstack *tetstack,
                  struct arraypoolstack *outstack,
                  int qualmeasure,
                  starreal bestmeans[],
                  starreal meanqualafter[],
                  starreal *minqualafter,
                  bool justfirstedge,
                  bool quiet)
{
    starreal outquality;           /* the quality of the current tet */
    struct improvetet *stacktet;   /* point to stack tet */
    struct improvetet *outtet;     /* point to stack tet */
    int contracted;                /* was edge / face removal successful */
    int numcontracted = 0;         /* number of edge contractions */
    int origstacksize;             /* number of tets in the original stack */
    int beforeid = lastjournalentry();
    struct arraypoolstack savestack;     /* save the input stack in case of failure */
    starreal minqualbefore, meanqualbefore[NUMMEANTHRESHOLDS];
    starreal minnow;
    
    *minqualafter = HUGEFLOAT;
    
    origstacksize = tetstack->top + 1;
    
    if (improvebehave.verbosity > 5 && outstack != NULL)
    {
        printf("here's the input stack:\n");
        printstack(mesh, tetstack);
    }
    /* compute worst input quality. do it global if no output stack */
    if (outstack != NULL)
    {
        stackquality(mesh, tetstack, qualmeasure, meanqualbefore, &minqualbefore);
    }
    else
    {
        meshquality(mesh, qualmeasure, meanqualbefore, &minqualbefore);
    }
    
    /* reset output stack */
    if (outstack != NULL)
    {
        stackrestart(outstack);
        /* save a copy of the input stack */
        stackinit(&savestack, sizeof(struct improvetet));
        copystack(tetstack, &savestack);
    }
    
    /* go through each tet on the stack */
    while (tetstack->top != STACKEMPTY)
    {
        /* pull the top tet off the stack */
        stacktet = (struct improvetet *) stackpop(tetstack);
        
        /* try to contract this edge */
        contracted = tryedgecontract(mesh,
                                     stacktet->verts[0], 
                                     stacktet->verts[1], 
                                     stacktet->verts[2], 
                                     stacktet->verts[3], 
                                     outstack,
                                     &outquality,
                                     true,
                                     justfirstedge);
        
        if (contracted == 1) numcontracted++;
        
        /* if nothing was done to this tet, push it on the output stack */
        if (contracted == 0 && outstack != NULL)
        {
            /* push this tet on the output stack */
            if (tetinstack(outstack,
                           stacktet->verts[0],
                           stacktet->verts[1],
                           stacktet->verts[2],
                           stacktet->verts[3]) == false)
            {
                /* push this tet on the output stack */
                outtet = (struct improvetet *) stackpush(outstack);
                outtet->quality = stacktet->quality;
                outtet->verts[0] = stacktet->verts[0];
                outtet->verts[1] = stacktet->verts[1];
                outtet->verts[2] = stacktet->verts[2];
                outtet->verts[3] = stacktet->verts[3];
            }
        }
        
        contracted = 0;
    }
    
    if (outstack != NULL)
    {
        if (improvebehave.verbosity > 4)
        {
            /*
            printf("here's the output stack:\n");
            printstack(mesh, outstack);
            */
            printf("just completed contraction improvment pass.\n");
            printf("    input stack had %d tets\n", origstacksize);
            printf("    output stack had %lu tets\n", outstack->top+1);
            printf("    number of edge contractions is %d\n", numcontracted);
            printf("    claimed input quality is            %g\n", pq(minqualbefore));
            printf("    worst quality in the output stack is %g\n", pq(worststackquality(mesh, outstack, qualmeasure)));
        }
        stackquality(mesh, outstack, qualmeasure, meanqualafter, minqualafter);
        
        /* if we didn't improve, undo this pass and indicate failure */
        if (*minqualafter < minqualbefore || (numcontracted == 0))
        {
            invertjournalupto(mesh, beforeid);
            /* send back the saved copy of the input stack as the output stack */
            stackdeinit(outstack);
            memcpy(outstack, &savestack, sizeof(struct arraypoolstack));
            /* make sure the outquality of the saved stack is same as incoming qual */
            stackquality(mesh, outstack, qualmeasure, meanqualbefore, &minnow);
            if (minnow != minqualbefore)
            {
                printf("worststackquality = %g, minqualbefore = %g, diff = %g", pq(minnow), pq(minqualbefore), pq(minnow - minqualbefore));
            }
            assert(minnow == minqualbefore);
            *minqualafter = minqualbefore;
            return false;
        }
        
        stackdeinit(&savestack);
        return true;
        
        /*
        *minqualafter = worstquality(mesh, qualmeasure);
        */
    }
    else
    {
        /* what's the worst quality element in the mesh now? */
        meshquality(mesh, qualmeasure, meanqualafter, minqualafter);
    }
    
    if (improvebehave.verbosity > 3 && quiet == false)
    {
        printf("Completed contraction pass on stack of %d tets\n", origstacksize);
        if (improvebehave.verbosity > 4)
        {
            printf("    Best previous means:\n");
            printmeans(bestmeans);
            printf("    Mean qualities after:\n");
            printmeans(meanqualafter);
        }
        printf("    Worst quality before: %g\n", pq(minqualbefore));
        if (minqualbefore < *minqualafter)
        {
            textcolor(BRIGHT, GREEN, BLACK);
        }
        printf("    Worst quality after:  %g\n", pq(*minqualafter));
        textcolor(RESET, WHITE, BLACK);
        if (improvebehave.verbosity > 4)
        {
            printf("    Edges contracted: %d\n", numcontracted);
        }
        assert(*minqualafter >= minqualbefore);
    }
    
    if (outstack != NULL)
    {
        stackdeinit(&savestack);
    }
    
    return true;
}

/* go after the worst tets with contraction */
void contractworst(struct tetcomplex *mesh,
                    int qualmeasure,
                    starreal percentinsert,
                    starreal bestmeans[],
                    starreal outmeanqual[],
                    starreal *outminqual,
                    bool desperate)
{
    starreal minqual, meanqual[NUMMEANTHRESHOLDS];/* quality of the worst tet in the mesh */
    struct arraypoolstack tetstack;      /* stack of tets  */
    starreal meshworstqual, origmeshworstqual;
    starreal fillthresh;
    
    /* initialize the tet stack */
    stackinit(&tetstack, sizeof(struct improvetet));
    
    meshquality(mesh, qualmeasure, meanqual, &minqual);
    
    if (desperate == false)
    {    
        /* fill the stack of with the worst percent insert tets */
        fillstackpercent(mesh, &tetstack, qualmeasure, 1.0, meanqual, &minqual);
        if (improvebehave.verbosity > 4)
        {
            textcolor(BRIGHT, MAGENTA, BLACK);
            printf("Attempting edge contraction on the worst %g percent of tets (%ld).\n", percentinsert * 100.0, tetstack.top);
            textcolor(RESET, WHITE, BLACK);
        }
    }
    else
    {
        if (minqual + QUALFROMDESPERATE < improvebehave.maxinsertquality[improvebehave.qualmeasure])
        {
            fillthresh = minqual + QUALFROMDESPERATE;
        }
        else if (minqual > improvebehave.maxinsertquality[improvebehave.qualmeasure])
        {
            fillthresh = minqual + QUALUPFROMDESPERATE;
        }
        else
        {
            fillthresh = improvebehave.maxinsertquality[improvebehave.qualmeasure];
        }
        fillstackqual(mesh, &tetstack, qualmeasure, fillthresh, meanqual, &minqual);
        if (improvebehave.verbosity > 4)
        {
            textcolor(BRIGHT, MAGENTA, BLACK);
            printf("Attempting DESPERATE edge contraction on the %ld tets with qual less than %g (%g degrees).\n", tetstack.top, fillthresh, pq(fillthresh));
            textcolor(RESET, WHITE, BLACK);
        }
    }
    
    origmeshworstqual = meshworstqual = minqual;
    
    /* perform insertion pass on stack of tets */
    contractpass(mesh, &tetstack, NULL, qualmeasure, bestmeans, outmeanqual, outminqual, false, false);
    
    /* free the stack of tets */
    stackdeinit(&tetstack);
    
    meshquality(mesh, qualmeasure, outmeanqual, outminqual);
    
    if (!improvebehave.fixedsmooth) 
    {
        if (*outminqual < origmeshworstqual)
        {
            printf("crap, mesh min qual = %g after contract pass, %g before.\n", pq(*outminqual), pq(origmeshworstqual));
        }
        assert(*outminqual >= origmeshworstqual);
    }
    
    /* print report */
    if (improvebehave.verbosity > 3)
    {
        if (meshworstqual > origmeshworstqual)
        {
            textcolor(BRIGHT, GREEN, BLACK);
            printf("    Worst angle in mesh improved from %g to %g degrees\n", pq(origmeshworstqual), pq(meshworstqual));
            textcolor(RESET, WHITE, BLACK);
        }
    }
}

  

<|start_filename|>vtkVmtk/Misc/vtkvmtkMeshVelocityStatistics.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkMeshVelocityStatistics.h,v $
Language:  C++
Date:      $Date: 2006/07/27 08:28:36 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkMeshVelocityStatistics - calculates average and RMS velocity statistics
// .SECTION Description
// .

#ifndef __vtkvmtkMeshVelocityStatistics_h
#define __vtkvmtkMeshVelocityStatistics_h

#include "vtkUnstructuredGridAlgorithm.h"
#include "vtkUnstructuredGrid.h"
#include "vtkvmtkWin32Header.h"

#include "vtkIdList.h"

class VTK_VMTK_MISC_EXPORT vtkvmtkMeshVelocityStatistics : public vtkUnstructuredGridAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkMeshVelocityStatistics,vtkUnstructuredGridAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkMeshVelocityStatistics *New();

  vtkSetObjectMacro(VelocityArrayIds,vtkIdList);
  vtkGetObjectMacro(VelocityArrayIds,vtkIdList);
  
  protected:
  vtkvmtkMeshVelocityStatistics();
  ~vtkvmtkMeshVelocityStatistics();  

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  vtkIdList* VelocityArrayIds;

  private:
  vtkvmtkMeshVelocityStatistics(const vtkvmtkMeshVelocityStatistics&);  // Not implemented.
  void operator=(const vtkvmtkMeshVelocityStatistics&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/arraypoolstack.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*  arraypoolstack                                                           */
/*                                                                           */
/*  This is a simple stack implementation based on arraypools.               */
/*                                                                           */
/*****************************************************************************/

/* initialize stack data structure */
void stackinit(struct arraypoolstack *stack, arraypoolulong objectbytes)
{
    /* call initialization for the arraypool */
    arraypoolinit(&(stack->pool), objectbytes, LOG2TETSPERSTACKBLOCK, 0);
    /* initialize the stack top index */
    stack->top = STACKEMPTY;
    stack->maxtop = STACKEMPTY;
}

/* reset stack data structure */
void stackrestart(struct arraypoolstack *stack)
{
    /* call restart for the arraypool */
    arraypoolrestart(&(stack->pool));
    /* initialize the stack top index */
    stack->top = STACKEMPTY;
    stack->maxtop = STACKEMPTY;
}

/* free the stack data structure */
void stackdeinit(struct arraypoolstack *stack)
{
    arraypooldeinit(&(stack->pool));
}

/* push a new element on the stack, return pointer where new element
   should go */
void* stackpush(struct arraypoolstack *stack)
{
    void *newobject;
    
    /* increment the top index */
    stack->top++;
    /* check whether we've allocated this index before */
    if (stack->top > stack->maxtop)
    {
        stack->maxtop = stack->top;
        /* we need to call force lookup to allocate new object */
        newobject = arraypoolforcelookup(&(stack->pool), (unsigned long) stack->top);
    }
    else
    {
        /* we can just do the lazy lookup */
        newobject = arraypoolfastlookup(&(stack->pool), (unsigned long) stack->top);
    }
    
    return newobject;
}

/* fetch the address of the top stack item */
void* stackpop(struct arraypoolstack *stack)
{
    /* we know the object is there so we can do the unsafe lookup */
    void *topobject = arraypoolfastlookup(&(stack->pool), (unsigned long) stack->top);
    stack->top--;
    assert(stack->top >= STACKEMPTY);
    
    return topobject;
}

/* convenience struct to use standard library quick sort funtion */
struct sorttet
{
    starreal qual;
    tag id;
};

/* compare two starreal numbers as qualities of tets to be sorted */
int comparesorttets(const void * a, const void * b)
{
    if ( ((struct sorttet *)a)->qual > ((struct sorttet *)b)->qual) return 1;
    if ( ((struct sorttet *)a)->qual < ((struct sorttet *)b)->qual) return -1;
    return 0;
}

/* function to sort an array of reals */
void qsorttets(struct sorttet *array,
               int arraylength)
{
    qsort(array, (size_t) arraylength, sizeof(struct sorttet), comparesorttets);
}

/* sort stack from worst quality to best */
/* TODO do in-place sort of arraypool? */
void sortstack(struct arraypoolstack *stack)
{
    int i;
    /* allocate an array of sorttets big enough for the stack */
    struct improvetet *tet, *fromtet, *totet;
    struct sorttet *sortarray;
    int size = stack->top + 1;
    
    struct arraypoolstack newstack;
    
    stackinit(&newstack, sizeof(struct improvetet));
    sortarray = (struct sorttet *) malloc((stack->top + 1) * sizeof(struct sorttet));
    
    if (improvebehave.verbosity > 5)
    {
        printf("starting sort of stack of size %lu... ", stack->top);
    }
    
    /* copy the qualities and tags into the array */
    for (i=0; i<=stack->top; i++)
    {
        /* fetch this item from the stack */
        tet = (struct improvetet *) arraypoolfastlookup(&(stack->pool), (unsigned long) i);
        
        /* copy into array */
        sortarray[i].id = i;
        sortarray[i].qual = tet->quality;
    }
    
    /* sort the array */
    qsorttets(sortarray, size);
    
    /* build up the new stack in the right order */
    for (i=stack->top; i>=0; i--)
    {
        /* get the right tet out of the unsorted stack */
        fromtet = (struct improvetet *) arraypoolfastlookup(&(stack->pool), (unsigned long) sortarray[i].id);
        totet = (struct improvetet *) stackpush(&newstack);
        
        /* copy it over */
        memcpy(totet, fromtet, sizeof(struct improvetet));
    }
    
    assert(stack->top == newstack.top);
    
    /* change output stack */
    stackdeinit(stack);
    memcpy(stack, &newstack, sizeof(struct arraypoolstack));
    
    /* deallocate sort array */
    free(sortarray);
    
    if (improvebehave.verbosity > 5)
    {
        printf("done\n");
    }
}

/* exactly copy one stack to another */
void copystack(struct arraypoolstack *fromstack,
               struct arraypoolstack *tostack)
{
    struct improvetet *fromtet, *totet;
    int i;
    
    /* reset the to stack */
    stackrestart(tostack);
    
    /* copy every element */
    for (i=0; i<=fromstack->top; i++)
    {
        /* get the right tet out of stack */
        fromtet = (struct improvetet *) arraypoolfastlookup(&(fromstack->pool), (unsigned long) i);
        totet = (struct improvetet *) stackpush(tostack);
        
        /* copy it over */
        memcpy(totet, fromtet, sizeof(struct improvetet));
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("copied stack\n");
        for (i=0; i<10; i++)
        {
            fromtet = (struct improvetet *) arraypoolfastlookup(&(fromstack->pool), (unsigned long) i);
            totet = (struct improvetet *) arraypoolfastlookup(&(tostack->pool), (unsigned long) i);
            printf("[%d] fromtet %g to tet %g", i, fromtet->quality, totet->quality);
            assert(fromtet->quality == totet->quality);
        }
    }
    
    assert(fromstack->top == tostack->top);
}

/* permute the order of a tet's vertices so that edge[0], edge[1]
   are the first two vertices */
void permuteedge(struct tetcomplex *mesh,
                 tag tet[4],
                 int edge[2])
{
    tag temptet[4];
    temptet[0] = tet[0];
    temptet[1] = tet[1];
    temptet[2] = tet[2];
    temptet[3] = tet[3];
    
    /* there are six cases. original tet is (0, 1, 2, 3) */
    /* edge  new permutation */
    /* 0 1   (0, 1, 2, 3)    */
    /* 0 2   (0, 2, 3, 1)    */
    /* 0 3   (0, 3, 2, 1)    */
    /* 1 2   (1, 2, 0, 3)    */
    /* 1 3   (1, 3, 2, 0)    */
    /* 2 3   (2, 3, 0, 1)    */
    
    if (edge[0] == 0 && edge[1] == 2)
    {
        tet[0] = temptet[0];
        tet[1] = temptet[2];
        tet[2] = temptet[3];
        tet[3] = temptet[1];
    }
    if (edge[0] == 0 && edge[1] == 3)
    {
        tet[0] = temptet[0];
        tet[1] = temptet[3];
        tet[2] = temptet[1];
        tet[3] = temptet[2];
    }
    if (edge[0] == 1 && edge[1] == 2)
    {
        tet[0] = temptet[1];
        tet[1] = temptet[2];
        tet[2] = temptet[0];
        tet[3] = temptet[3];
    }
    if (edge[0] == 1 && edge[1] == 3)
    {
        tet[0] = temptet[1];
        tet[1] = temptet[3];
        tet[2] = temptet[2];
        tet[3] = temptet[0];
    }
    if (edge[0] == 2 && edge[1] == 3)
    {
        tet[0] = temptet[2];
        tet[1] = temptet[3];
        tet[2] = temptet[0];
        tet[3] = temptet[1];
    }
    
    /* should have positive orientation */
    assert(tetvolume(mesh, tet[0], tet[1], tet[2], tet[3]) > 0.0);
}

/* peer into a stack of tets to see if a tet starting with edge (vtx1, vtx2)
   is in there somewhere */
bool tetinstackedge(struct arraypoolstack *tetstack,
                    tag vtx1, tag vtx2)
{
    int i;                  /* loop index */
    struct improvetet *tet; /* current tet */
    
    for (i=0; i<=tetstack->top; i++)
    {
        /* fetch this item from the stack */
        tet = (struct improvetet *) arraypoolfastlookup(&(tetstack->pool), (unsigned long) i);
        /* does it start with the vertex we were looking for? */
        if (tet->verts[0] == vtx1 && tet->verts[1] == vtx2) return true;
    }
    return false;
}

/* given a mesh and a minimum and maximum edge length,
   fill two stacks with tets edges shorter than the minimum
   or longer than the maximum. Each unique edge is represented
   in just one tet. Order the vertices in the tets
   such that the too short (too long) edge comes first */
void filledgestacks(struct tetcomplex *mesh,
                    struct arraypoolstack *longstack,
                    struct arraypoolstack *shortstack,
                    starreal minlength,
                    starreal maxlength,
                    starreal *minedge,
                    starreal *maxedge,
                    starreal *meanedge)
{
    struct tetcomplexposition pos; /* position of iterator in the mesh */
    tag tet[4];                    /* the current tet */
    int numedges = 0;              /* number of edges in the mesh */
    tag adjacencies[2];
    tag origin;
    tag destin;
    tag apex;
    tag stopvtx;
    tag searchvtx = NOTATAG;
    tag swaptag;
    int writeflag = 0;
    int i;
    struct improvetet *stacktet;   /* point to stack tet */
    int edge[2];
    starreal edgev[3];
    starreal origcoord[3], destcoord[3], E[3][3];
    starreal edgelength;
    
    *minedge = HUGEFLOAT;
    *maxedge = 0.0;
    
    /* make sure the stacks are empty */
    if (longstack != NULL) stackrestart(longstack);
    if (shortstack != NULL) stackrestart(shortstack);
    
    /* initialize the iterator over the mesh */
    tetcomplexiteratorinit(mesh, &pos);
    /* retrieve the first tet in the mesh */
    tetcomplexiteratenoghosts(&pos, tet);
    
    /* for each tet */
    while (tet[0] != STOP) 
    {
        /* Look at all six edges of the tetrahedron. */
        /* Iteration over unique edges taken from Jonathan's outputedges() */
        for (i = 0; i < 6; i++) 
        {
            if (tet[0] < tet[1]) 
            {
                origin = tet[0];
                destin = tet[1];
                apex = tet[2];
                stopvtx = tet[3];
                edge[0] = 0;
                edge[1] = 1;
            } 
            else
            {
                origin = tet[1];
                destin = tet[0];
                apex = tet[3];
                stopvtx = tet[2];
                edge[0] = 1;
                edge[1] = 0;
            }
            
            searchvtx = apex;
            writeflag = 1;
            do 
            {
                if (!tetcomplexadjacencies(mesh, origin, destin, searchvtx,
                                         adjacencies)) 
                {
                    printf("Error computing edge statistics:\n");
                    printf("  Complex returned tetrahedron that can't be queried.\n");
                    internalerror();
                }
                if (adjacencies[0] == GHOSTVERTEX) 
                {
                    writeflag = searchvtx == apex;
                }
                searchvtx = adjacencies[0];
                if (searchvtx < apex) 
                {
                    writeflag = 0;
                }
            } 
            while (writeflag && (searchvtx != stopvtx) && (searchvtx != GHOSTVERTEX));
            
            /* if this is an edge that hasn't been counted yet */
            if (writeflag) 
            {
                /* measure the length of this edge */
                vcopy(((struct vertex *) tetcomplextag2vertex(mesh, origin))->coord, origcoord);
                vcopy(((struct vertex *) tetcomplextag2vertex(mesh, destin))->coord, destcoord);
                
                /* if anisotropic meshing is enabled, warp the points according the
                   deformation tensor at their barycenter */
                if (improvebehave.anisotropic)
                {
                    /* fetch the deformation tensor at the midpoint of this tet */
                    edgetensor(mesh, origin, destin, E);
                    
                    /* transform each vertex */
                    tensortransform(origcoord, origcoord, E);
                    tensortransform(destcoord, destcoord, E);
                }
                
                vsub(destcoord, origcoord, edgev);
                edgelength = vlength(edgev);
                
                /* keep track of minimum, maximum and average edge lengths */
                if (edgelength < *minedge) *minedge = edgelength;
                if (edgelength > *maxedge) *maxedge = edgelength;
                *meanedge += edgelength;
                numedges++;
                
                /* if this edge is too short, push it on the appropriate stack */
                if (shortstack != NULL)
                {
                    if (edgelength < minlength && !tetinstackedge(shortstack, origin, destin))
                    {
                        /* push this tet on the "too short" stack */
                        stacktet = (struct improvetet *) stackpush(shortstack);
                        stacktet->quality = edgelength;
                        stacktet->verts[0] = tet[0];
                        stacktet->verts[1] = tet[1];
                        stacktet->verts[2] = tet[2];
                        stacktet->verts[3] = tet[3];

                        /* permute the vertices of the tet on the stack so
                           that the shortest edge comes as the first two verts */
                        permuteedge(mesh, stacktet->verts, edge);
                    }
                }
                
                /* if this edge is too long push it on the appropriate stack */
                if (longstack != NULL)
                {
                    if (edgelength > maxlength && !tetinstackedge(longstack, origin, destin))
                    {
                        /* push this tet on the "too short" stack */
                        stacktet = (struct improvetet *) stackpush(longstack);
                        stacktet->quality = edgelength;
                        stacktet->verts[0] = tet[0];
                        stacktet->verts[1] = tet[1];
                        stacktet->verts[2] = tet[2];
                        stacktet->verts[3] = tet[3];

                        /* permute the vertices of the tet on the stack so
                           that the longest edge comes as the first two verts */
                        permuteedge(mesh, stacktet->verts, edge);
                    }
                }
            }
            
            /* The following shift cycles (tet[0], tet[1]) through all the edges   */
            /*   while maintaining the tetrahedron's orientation.  The schedule is */
            /*   i = 0:  0 1 2 3 => 1 2 0 3                                        */
            /*   i = 1:  1 2 0 3 => 1 3 2 0                                        */
            /*   i = 2:  1 3 2 0 => 3 2 1 0                                        */
            /*   i = 3:  3 2 1 0 => 3 0 2 1                                        */
            /*   i = 4:  3 0 2 1 => 0 2 3 1                                        */
            /*   i = 5:  0 2 3 1 => 0 1 2 3 (which isn't used).                    */
            if ((i & 1) == 0) 
            {
                swaptag = tet[0];
                tet[0] = tet[1];
                tet[1] = tet[2];
                tet[2] = swaptag;
            } 
            else
            {
                swaptag = tet[3];
                tet[3] = tet[2];
                tet[2] = tet[1];
                tet[1] = swaptag;
            }
        }
        
        /* fetch the next tet from the mesh */
        tetcomplexiteratenoghosts(&pos, tet);
    }
    
    *meanedge /= numedges;
    
    if (improvebehave.verbosity > 4)
    {
        printf("Just built edge stacks.\n");
        printf("    Total edges in mesh: %d\n", numedges);
        if (shortstack != NULL) printf("    Short stack has %d tets with edge shorter than %g\n", (int) shortstack->top+1, minlength);
        if (longstack != NULL) printf("    Long stack has %d tets with edge longer than %g\n", (int) longstack->top+1, maxlength);
    }
}


/* given a mesh and a quality threshold,
   return a stack of tets with quality 
   at or below that threshold. this function
   assumes that the stack has already been 
   initialized. */
void fillstackqual(struct tetcomplex *mesh,
                   struct arraypoolstack *stack,
                   int qualmeasure,
                   starreal threshold,
                   starreal meanquals[],
                   starreal *minqual)
{
    struct tetcomplexposition pos; /* position of iterator in the mesh */
    tag tet[4];                    /* the current tet */
    starreal quality;                /* the quality of the current tet */
    struct improvetet *stacktet;   /* point to stack tet */
    int numtets = 0;
    int i;
    
    /* make sure the stack is empty */
    stackrestart(stack);
    
    /* initialize the iterator over the mesh */
    tetcomplexiteratorinit(mesh, &pos);
    /* retrieve the first tet in the mesh */
    tetcomplexiteratenoghosts(&pos, tet);
    
    *minqual = HUGEFLOAT;
    for (i=0; i<NUMMEANTHRESHOLDS; i++)
    {
        meanquals[i] = 0.0;
    }
    
    /* for each tet */
    while (tet[0] != STOP) 
    {
        /* compute the quality of this tet */
        quality = tetquality(mesh, tet[0], tet[1], tet[2], tet[3], qualmeasure);
        
        /* keep track of minimum quality */
        if (quality < *minqual) *minqual = quality;
        
        /* if this tet is worse than the threshold */
        if (quality < threshold)
        {
            /* track thresholded mean qualities only for tets actually included in the stack */
            numtets++;
            for (i=0; i<NUMMEANTHRESHOLDS; i++)
            {
                meanquals[i] += (quality < meanthresholds[improvebehave.qualmeasure][i]) ? quality : meanthresholds[improvebehave.qualmeasure][i];
            }
            
            /* push this tet on the "to be fixed" stack */
            stacktet = (struct improvetet *) stackpush(stack);
            stacktet->quality = quality;
            stacktet->verts[0] = tet[0];
            stacktet->verts[1] = tet[1];
            stacktet->verts[2] = tet[2];
            stacktet->verts[3] = tet[3];
        }
        
        /* fetch the next tet from the mesh */
        tetcomplexiteratenoghosts(&pos, tet);
    }
    
    /* compute thresholded means */
    for (i=0; i<NUMMEANTHRESHOLDS; i++)
    {
        if (numtets != 0)
        {
            meanquals[i] /= (starreal) numtets;
        }
        else
        {
            meanquals[i] = 0.0;
        }
    }
    
    /* sort the stack of tets from worst to best */
    sortstack(stack);
}

/* given a mesh and a percentage p,
   return the worst numtets * p tets in the mesh */
void fillstackpercent(struct tetcomplex *mesh,
                      struct arraypoolstack *stack,
                      int qualmeasure,
                      starreal percent,
                      starreal meanquals[],
                      starreal *minqual)
{
    struct improvetet *stacktet;   /* point to stack tet */
    struct improvetet *outstacktet;
    int i;
    
    int numouttets = 0.0;
    
    /* create a local stack for the global build */
    struct arraypoolstack alltetstack;
    
    assert(percent > 0.0 && percent <= 1.0);
    
    stackinit(&alltetstack, sizeof(struct improvetet));
    
    /* fill it with every tet in the mesh */
    fillstackqual(mesh, &alltetstack, qualmeasure, HUGEFLOAT, meanquals, minqual);
    
    /* sort it from worst to best */
    sortstack(&alltetstack);
    
    /* figure out how many tets to take */
    numouttets = (int) (percent * ((starreal) alltetstack.top + 1.0));
    assert(numouttets <= alltetstack.top + 1);
    
    if (numouttets > MAXINSERTTETS)
    {
        numouttets = MAXINSERTTETS;
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("in percent stack num out tets is %d\n", numouttets);
    }
    
    /* make sure the output stack is empty */
    stackrestart(stack);
    
    /* now, pop numouttets off the output stack */
    for (i=0; i<numouttets; i++)
    {
        /* pull the top tet off the stack */
        stacktet = (struct improvetet *) stackpop(&alltetstack);
        
        /* make sure there are still tets in the stack */
        if (alltetstack.top == STACKEMPTY) break;
        
        /* make sure this tet still exists */
        if (tetexists(mesh,
                      stacktet->verts[0],
                      stacktet->verts[1],
                      stacktet->verts[2],
                      stacktet->verts[3]) == false) continue;
                      
        if (improvebehave.verbosity > 5)
        {
            printf("adding tet with qual %g to outstack\n", stacktet->quality);
        }
        
        outstacktet = (struct improvetet *) stackpush(stack);
        outstacktet->quality = stacktet->quality;
        outstacktet->verts[0] = stacktet->verts[0];
        outstacktet->verts[1] = stacktet->verts[1];
        outstacktet->verts[2] = stacktet->verts[2];
        outstacktet->verts[3] = stacktet->verts[3];
    }
    
    /* sort output from worst to best */
    sortstack(stack);
    
    if (improvebehave.verbosity > 5)
    {
        printf("done finding worst %g percent of tets, returning stack of %lu of them.\n", percent * 100.0, stack->top + 1);
    }
}

/* run through a stack of tets, initializing each vertex with
   a flag indicating that it has not yet been smoothed */
void initsmoothedvertlist(struct arraypoolstack *tetstack,
                          struct arraypool *vertlist)
{
    int i,j;                  /* loop index */
    struct improvetet *tet;   /* current tet */
    
    if (improvebehave.verbosity > 5)
    {
        printf("Initializing %lu tets of vertices to not smoothed... ", tetstack->top);
    }
    
    /* for every vertex in the stack */
    for (i=0; i<=tetstack->top; i++)
    {
        /* fetch this item from the stack */
        tet = (struct improvetet *) arraypoolfastlookup(&(tetstack->pool), (unsigned long) i);
        /* for each vertex */
        for (j = 0; j<4; j++)
        {
            /* initialize this vertex to not smoothed */
            *((bool *) arraypoolforcelookup(vertlist, tet->verts[j])) = false;
        }
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("done.\n");
    }
}

/* peer into a stack of tets to see if a tet starting with vtx
   is in there somewhere */
bool tetinstackfirstvert(struct arraypoolstack *tetstack,
                tag vtx)
{
    int i;                  /* loop index */
    struct improvetet *tet; /* current tet */
    
    for (i=0; i<=tetstack->top; i++)
    {
        /* fetch this item from the stack */
        tet = (struct improvetet *) arraypoolfastlookup(&(tetstack->pool), (unsigned long) i);
        /* does it start with the vertex we were looking for? */
        if (tet->verts[0] == vtx) return true;
    }
    return false;
}

/* peer into a stack of vertices to see if a particular tag is present */
bool vertinstack(struct arraypoolstack *vertstack,
                         tag vtx)
{
    int i;     /* loop index */
    tag *curv; /* current tet */
    int j=0;
    
    for (i=0; i<=vertstack->top; i++)
    {
        j++;
        
        /* fetch this item from the stack */
        curv = (tag *) arraypoolfastlookup(&(vertstack->pool), (unsigned long) i);
        /* does it start with the vertex we were looking for? */
        if (*curv == vtx) return true;
    }
    return false;
}

/* peer into a stack of tets to see if a tet
   is in there somewhere */
bool tetinstack(struct arraypoolstack *tetstack,
                tag v1,
                tag v2,
                tag v3,
                tag v4)
{
    int i;                  /* loop index */
    struct improvetet *tet; /* current tet */
    
    for (i=0; i<=tetstack->top; i++)
    {
        /* fetch this item from the stack */
        tet = (struct improvetet *) arraypoolfastlookup(&(tetstack->pool), (unsigned long) i);
        /* does this tet match? */
        if (sametet(tet->verts[0], tet->verts[1], tet->verts[2], tet->verts[3],
                    v1, v2, v3, v4))
        {
            return true;
        }
    }
    return false;
}

/* append the contents of one stack to the top of another */
/* only adds tets if they do not already exist in tostack */
void appendstack(struct arraypoolstack *fromstack,
                 struct arraypoolstack *tostack)
{
    struct improvetet *fromtet, *totet;
    int i;
    
    /* copy every element */
    for (i=0; i<=fromstack->top; i++)
    {
        /* get the right tet out of stack */
        fromtet = (struct improvetet *) arraypoolfastlookup(&(fromstack->pool), (unsigned long) i);
        
        /* if this tet is not in the target stack */
        if (tetinstack(tostack, fromtet->verts[0], fromtet->verts[1], fromtet->verts[2], fromtet->verts[3]) == false)
        {
            totet = (struct improvetet *) stackpush(tostack);
        
            /* copy it over */
            memcpy(totet, fromtet, sizeof(struct improvetet));
        }
    }
}

/* compute the mean and minimum element
   qualities in the meash (multiple thresholded means) */
void meshquality(struct tetcomplex *mesh,
                    int qualmeasure,
                    starreal *meanqual,
                    starreal *minqual)
{
    struct arraypoolstack tetstack;   /* stack of tets  */
    
    stackinit(&tetstack, sizeof(struct improvetet));
    
    /* fill the stack of tets with all tets in the mesh */
    fillstackqual(mesh, &tetstack, qualmeasure, HUGEFLOAT, meanqual, minqual);
    
    stats.finishworstqual = *minqual;
    
    /* free the stack of tets */
    stackdeinit(&tetstack);
}

/* return the worst quality of all elements in the mesh */
double worstquality(struct tetcomplex*mesh)
{
    starreal meanqual[NUMMEANTHRESHOLDS];
    starreal minqual;
    
    struct arraypoolstack tetstack;   /* stack of tets  */
    
    stackinit(&tetstack, sizeof(struct improvetet));
    
    /* fill the stack of tets with all tets in the mesh */
    fillstackqual(mesh, &tetstack, improvebehave.qualmeasure, HUGEFLOAT, meanqual, &minqual);
    
    /* free the stack of tets */
    stackdeinit(&tetstack);
    
    return minqual;
}

/* find the meand and minimum qualities
   of all the tets in the stack (that still exist) */
void stackquality(struct tetcomplex *mesh,
                  struct arraypoolstack *tetstack,
                  int qualmeasure,
                  starreal meanqual[],
                  starreal *minqual)
{
    int i,j;                  /* loop index */
    struct improvetet *tet;   /* current tet */
    int nonexist = 0;
    starreal worstqual = HUGEFLOAT;
    int numtets = 0;
    starreal newqual;
    
    for (j=0; j<NUMMEANTHRESHOLDS; j++)
    {
        meanqual[j] = 0.0;
    }
    
    for (i=0; i<=tetstack->top; i++)
    {
        /* fetch this item from the stack */
        tet = (struct improvetet *) arraypoolfastlookup(&(tetstack->pool), (unsigned long) i);

        /* check that it exists */
        if (tetexists(mesh, tet->verts[0], tet->verts[1], tet->verts[2], tet->verts[3]) == 0)
        {
            nonexist++;
            continue;
        }
        
        /* it exists, compute it's quality */
        newqual = tetquality(mesh, tet->verts[0], tet->verts[1], tet->verts[2], tet->verts[3], qualmeasure);
        
        /* track thresholded mean qualities only for tets actually included in the stack */
        numtets++;
        for (j=0; j<NUMMEANTHRESHOLDS; j++)
        {
            meanqual[j] += (newqual < meanthresholds[improvebehave.qualmeasure][j]) ? newqual : meanthresholds[improvebehave.qualmeasure][j];
        }
        
        /* is this a new low ? */
        if (newqual < worstqual) worstqual = newqual;

    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("non-existent tets: %d / %lu\n", nonexist, tetstack->top+1);
    }
    
    *minqual = worstqual;
    
    /* compute thresholded means */
    for (i=0; i<NUMMEANTHRESHOLDS; i++)
    {
        meanqual[i] /= (starreal) numtets;
    }
}

/* find the longest and shortest edge length in a stack of tets */
void longshortstack(struct tetcomplex *mesh,
                    struct arraypoolstack *tetstack,
                    starreal *longest,
                    starreal *shortest)
{
    int i;                  /* loop index */
    struct improvetet *tet; /* current tet */
    int nonexist = 0;
    starreal thislong, thisshort;
    int edge[2];
    *longest = 0.0;
    *shortest = HUGEFLOAT;
    
    for (i=0; i<=tetstack->top; i++)
    {
        /* fetch this item from the stack */
        tet = (struct improvetet *) arraypoolfastlookup(&(tetstack->pool), (unsigned long) i);

        /* check that it exists */
        if (tetexists(mesh, tet->verts[0], tet->verts[1], tet->verts[2], tet->verts[3]) == 0)
        {
            nonexist++;
            continue;
        }
        
        /* it exists, compute it's longest and shortest edge */
        thislong = tetedge(mesh, tet->verts[0], tet->verts[1], tet->verts[2], tet->verts[3], edge, true);
        thisshort = tetedge(mesh, tet->verts[0], tet->verts[1], tet->verts[2], tet->verts[3], edge, false);
        
        if (thislong > *longest) *longest = thislong;
        if (thisshort < *shortest) *shortest = thisshort;
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("non-existent tets: %d / %lu\n", nonexist, tetstack->top+1);
    }
}

/* find the worst quality of all the tets in the stack (that still exist) */
starreal worststackquality(struct tetcomplex *mesh,
                         struct arraypoolstack *tetstack,
                         int qualmeasure)
{
    int i;                  /* loop index */
    struct improvetet *tet; /* current tet */
    int nonexist = 0;
    starreal worstqual = HUGEFLOAT;
    starreal newqual;
    
    for (i=0; i<=tetstack->top; i++)
    {
        /* fetch this item from the stack */
        tet = (struct improvetet *) arraypoolfastlookup(&(tetstack->pool), (unsigned long) i);

        /* check that it exists */
        if (tetexists(mesh, tet->verts[0], tet->verts[1], tet->verts[2], tet->verts[3]) == 0)
        {
            nonexist++;
            continue;
        }
        
        /* it exists, compute it's quality */
        newqual = tetquality(mesh, tet->verts[0], tet->verts[1], tet->verts[2], tet->verts[3], qualmeasure);
        
        /* is this a new low ? */
        if (newqual < worstqual) worstqual = newqual;

    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("non-existent tets: %d / %lu\n", nonexist, tetstack->top+1);
    }
    
    return worstqual;
}

/* print out all the tets in a stack */
void printstack(struct tetcomplex *mesh,
                struct arraypoolstack *tetstack)
{
    int i;                  /* loop index */
    struct improvetet *tet; /* current tet */
    
    printf("{");
    for (i=0; i<=tetstack->top; i++)
    {
        /* fetch this item from the stack */
        tet = (struct improvetet *) arraypoolfastlookup(&(tetstack->pool), (unsigned long) i);

        /* print out this tet */
        printtetverts(mesh, tet->verts);
        if (i != tetstack->top) printf(",\n");
    }
    printf("};\n");
}












<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/showme.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*    ,d88""\ 888                                   o    o                   */
/*    8888    888o888,  o88""o Y88b    o    /      d8b  d8b      o88888o     */
/*    "Y88b   888  888 d888   b Y88b  d8b  /      d888bdY88b    d888  88b    */
/*     "Y88b, 888  888 8888   8  Y888/Y88b/      / Y88Y Y888b   8888oo888    */
/*       8888 888  888 q888   p   Y8/  Y8/      /   YY   Y888b  q888         */
/*    \_o88P' 888  888  "88oo"     Y    Y      /          Y888b  "88oooo"    */
/*                                                                           */
/*  A Display Program for Meshes and More.                                   */
/*  (showme.c)                                                               */
/*                                                                           */
/*  Version 1.61                                                             */
/*  5 July 2009                                                              */
/*                                                                           */
/*  Portions of Show Me written prior to June 30, 1998 are                   */
/*  Copyright 1995, 1996, 1998                                               */
/*  <NAME>                                                */
/*  965 Sutter Street #815                                                   */
/*  San Francisco, California  94109-6082                                    */
/*  <EMAIL>                                                      */
/*                                                                           */
/*  Portions of Show Me written after June 30, 1998 are in the public        */
/*  domain, but Show Me as a whole is not.  All rights reserved.             */
/*                                                                           */
/*  This version of Show Me is provided as part of Stellar, a program for    */
/*  improving tetrahedral meshes.  Stellar and this version of Show Me are   */
/*  open source software provided under the Berkeley Source Distribution     */
/*  (BSD) license, which follows.  If you want to use Stellar in a           */
/*  commercial product, the BSD license permits you to do so freely.  Bryan  */
/*  Klingner and I request that you kindly send me an email to let us know   */
/*  what products include Stellar, but it is not a legal requirement.        */
/*                                                                           */
/*  ======================= BSD license begins here. ======================= */
/*                                                                           */
/*  Redistribution and use in source and binary forms, with or without       */
/*  modification, are permitted provided that the following conditions are   */
/*  met:                                                                     */
/*                                                                           */
/*  - Redistributions of source code must retain the above copyright notice, */
/*    this list of conditions and the following disclaimer.                  */
/*                                                                           */
/*  - Redistributions in binary form must reproduce the above copyright      */
/*    notice, this list of conditions and the following disclaimer in the    */
/*    documentation and/or other materials provided with the distribution.   */
/*                                                                           */
/*  - Neither the name of <NAME> nor the name of the University   */
/*    of California nor the names of its contributors may be used to endorse */
/*    or promote products derived from this software without specific prior  */
/*    written permission.                                                    */
/*                                                                           */
/*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS  */
/*  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED    */
/*  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A          */
/*  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT      */
/*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    */
/*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
/*  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR   */
/*  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF   */
/*  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     */
/*  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS       */
/*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.             */
/*                                                                           */
/*  ======================== BSD license ends here. ======================== */
/*                                                                           */
/*  Additional disclaimer:  Neither I nor any institution I have been        */
/*  associated with warrant this code in any way whatsoever.  This code is   */
/*  provided "as is".  Use at your own risk.                                 */
/*                                                                           */
/*  Hypertext instructions for Show Me will some day be available at         */
/*                                                                           */
/*      http://www.cs.cmu.edu/~quake/showme.html                             */
/*                                                                           */
/*  If you make any improvements to this code, please please please let me   */
/*  know, so that I may obtain the improvements.  Even if you don't change   */
/*  the code, I'd still love to hear what it's being used for.               */
/*                                                                           */
/*****************************************************************************/


/*  For single precision (which will save some memory and reduce paging),    */
/*  define the symbol SINGLE by using the -DSINGLE compiler switch or by     */
/*  writing "#define SINGLE" below.                                          */
/*                                                                           */
/*  For double precision (which will allow you to display finer meshes),     */
/*  leave SINGLE undefined.                                                  */

/* #define SINGLE */

#ifdef SINGLE
typedef float showmereal;
#else /* not SINGLE */
typedef double showmereal;
#endif /* not SINGLE */

/*  On some machines, my exact arithmetic routines might be defeated by the  */
/*  use of internal extended precision floating-point registers.  The best   */
/*  way to solve this problem is to set the floating-point registers to use  */
/*  single or double precision internally.  On 80x86 processors, this may be */
/*  accomplished by setting the CPU86 symbol in Microsoft operating systems, */
/*  or the LINUX symbol in Linux.                                            */
/*                                                                           */
/*  An inferior solution is to declare certain values as `volatile', thus    */
/*  forcing them to be stored to memory and rounded off.  Unfortunately,     */
/*  this solution might slow Triangle down quite a bit.  To use volatile     */
/*  values, write "#define INEXACT volatile" below.  Normally, however,      */
/*  INEXACT should be defined to be nothing.  ("#define INEXACT".)           */
/*                                                                           */
/*  For more discussion, see Section 5 of my paper, "Adaptive Precision      */
/*  Floating-Point Arithmetic and Fast Robust Geometric Predicates" (also    */
/*  available as Section 6.6 of my dissertation).                            */

/* #define CPU86 */
/* #define LINUX */

/* On some machines, the exact arithmetic routines might be defeated by the  */
/*   use of internal extended precision floating-point registers.  Sometimes */
/*   this problem can be fixed by defining certain values to be volatile,    */
/*   thus forcing them to be stored to memory and rounded off.  This isn't   */
/*   a good solution, though, as it slows Pyramid down.                      */
/*                                                                           */
/* To try this out, write "#define INEXACT volatile" below.  Normally,       */
/*   however, INEXACT should be defined to be nothing.  ("#define INEXACT".) */

#define INEXACT /* Nothing */
/* #define INEXACT volatile */

/*  Maximum number of characters in a file name (including the null).        */

#define FILENAMESIZE 2048

/*  Maximum number of characters in a line read from a file (including the   */
/*  null).                                                                   */

#define INPUTLINESIZE 1024

#define STARTWIDTH 414
#define STARTHEIGHT 414
#define MINWIDTH 50
#define MINHEIGHT 50
#define BUTTONHEIGHT 21
#define BUTTONROWS 4
#define PANELHEIGHT (BUTTONHEIGHT * BUTTONROWS)
#define MAXCOLORS 64
#define MAXGRAYS 64

#define IMAGE_TYPES 8
#define NOTHING -1
#define NODE 0
#define POLY 1
#define ELE 2
#define EDGE 3
#define PART 4
#define ADJ 5
#define VORO 6
#define DATA 7

#define TRIMLEFT 0
#define TRIMRIGHT 1
#define TRIMUP 2
#define TRIMDOWN 3

#define STARTEXPLOSION 0.5

#define DEG2RAD 0.0174532925199433
#define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#ifdef CPU86
#include <float.h>
#endif /* CPU86 */
#ifdef LINUX
#include <fpu_control.h>
#endif /* LINUX */


/*  `showmelong' and `showmeulong' are the types of integer (signed and      */
/*  unsigned, respectively) of most of the indices used internally and       */
/*  externally by ShowMe, including vertex and tetrahedron numbers.  They    */
/*  determine the number of internal data structures that can be allocated,  */
/*  so long choices (e.g. ptrdiff_t and size_t, defined in stddef.h) are     */
/*  recommended.  If the number of tetrahedra might be around 2^28 or more,  */
/*  use 64-bit integers.  On a machine with 32-bit pointers (memory          */
/*  addresses), though, there's no point using integers bigger than 32 bits. */
/*  On a machine with limited memory, smaller integers might allow you to    */
/*  create larger meshes.                                                    */

typedef ptrdiff_t showmelong;
typedef size_t showmeulong;


struct tetra {
  /* Which tetrahedron is opposite vertex 0-3?  Zero means none.  A number */
  /* less than zero means it's -neighbor[i], but the neighbor has been     */
  /* marked invisible.                                                     */
  showmelong neighbor[4];
  showmelong nexttet;        /* Links list of tetrahedra with exposed faces. */
  int invisible;         /* True if this tetrahedron should not be rendered. */
};

/*  A necessary forward declaration.                                         */

int load_image();

/*  Global constants.                                                        */

showmereal splitter; /* Used to split real factors for exact multiplication. */
showmereal epsilon;                       /* Floating-point machine epsilon. */
showmereal o3derrboundA, o3derrboundB, o3derrboundC, resulterrbound;


struct tetra *tetraptr;

Display *display;
int screen;
Window rootwindow;
Window mainwindow;
Window quitwin;
Window leftwin;
Window rightwin;
Window upwin;
Window downwin;
Window resetwin;
Window pswin;
Window epswin;
Window expwin;
Window exppluswin;
Window expminuswin;
Window widthpluswin;
Window widthminuswin;
Window versionpluswin;
Window versionminuswin;
Window fillwin;
Window motionwin;
Window rotatewin[6];
Window rotateamtwin;
Window wireframeoptionwin;
Window perspectivewin;
Window perspluswin;
Window persminuswin;
Window cutleftwin;
Window cutrightwin;
Window cutupwin;
Window cutdownwin;
Window qualitywin;
Window nodewin[2];
Window polywin[2];
Window elewin[2];
Window edgewin[2];
Window partwin[2];
Window adjwin[2];
Window voronoiwin[2];
Window datawin[2];

int windowdepth;
XEvent event;
Colormap rootmap;
XFontStruct *myfont;
unsigned int width, height;
int black, white;
unsigned int showme_foreground;
GC fontgc;
GC blackfontgc;
GC linegc;
GC trianglegc;
int bitreverse[MAXCOLORS];
unsigned int colors[MAXCOLORS];
XColor rgb[MAXCOLORS];
unsigned int grays[MAXGRAYS];
XColor gray[MAXGRAYS];
int colordisplay;
int wireframe = 0;
int perspective = 0;
int motion = 0;

int start_image, current_image;
int start_inc, current_inc;
int loweriteration;
unsigned int line_width;
int loaded[2][IMAGE_TYPES];
showmereal xlo[2][IMAGE_TYPES], ylo[2][IMAGE_TYPES], zlo[2][IMAGE_TYPES];
showmereal xhi[2][IMAGE_TYPES], yhi[2][IMAGE_TYPES], zhi[2][IMAGE_TYPES];
showmereal xscale, yscale;
showmereal xoffset, yoffset;
int zoom;

showmelong nodes[2];
int nodedim[2];
showmereal *nodeptr[2];
showmelong polynodes[2];
int polydim[2];
showmelong polyedges[2], polyholes[2];
showmereal *polynodeptr[2], *polyholeptr[2];
showmelong *polysegptr[2];
showmelong elems[2];
int elecorners[2];
showmelong *eleptr[2];
showmelong edges[2];
showmelong *edgeptr[2];
showmereal *normptr[2];
int subdomains[2];
int *partition[2];
showmereal *subdomcenter[2], *subdomshift[2];
int adjsubdomains[2];
int *adjptr[2];
showmelong vnodes[2];
int vnodedim[2];
showmereal *vnodeptr[2];
showmelong vedges[2];
showmelong *vedgeptr[2];
showmereal *vnormptr[2];
showmelong datavalues[2];
int datadim[2];
showmereal *dataptr[2];
showmereal datahist[2][2]; /* Hi & Lo for adaptive scaling of 2D height info */
int firstnumber[2];

int quiet, fillelem, bw_ps, explode;
showmereal explosion;

unsigned long randomseed;                     /* Current random number seed. */

int dlist_drawn = 0;
showmereal amtLeft = 0.0, amtUp = 0.0;
showmereal lightsourcex = 0.1;
showmereal lightsourcey = 0.7937;
showmereal lightsourcez = 0.6;

char filename[FILENAMESIZE];
char nodefilename[2][FILENAMESIZE];
char polyfilename[2][FILENAMESIZE];
char elefilename[2][FILENAMESIZE];
char edgefilename[2][FILENAMESIZE];
char partfilename[2][FILENAMESIZE];
char adjfilename[2][FILENAMESIZE];
char vnodefilename[2][FILENAMESIZE];
char vedgefilename[2][FILENAMESIZE];
char datafilename[2][FILENAMESIZE];

/* Original colors */
/*
char *colorname[] = {"aquamarine", "red", "green yellow", "magenta",
                     "yellow", "green", "orange", "blue",
                     "white", "sandy brown", "cyan", "moccasin",
                     "cadet blue", "coral", "cornflower blue", "sky blue",
                     "firebrick", "forest green", "gold", "goldenrod",
                     "gray", "hot pink", "chartreuse", "pale violet red",
                     "indian red", "khaki", "lavender", "light blue",
                     "light gray", "light steel blue", "lime green", "azure",
                     "maroon", "medium aquamarine", "dodger blue", "honeydew",
                     "medium orchid", "medium sea green", "moccasin",
                     "medium slate blue", "medium spring green",
                     "medium turquoise", "medium violet red",
                     "orange red", "chocolate", "light goldenrod",
                     "orchid", "pale green", "pink", "plum",
                     "purple", "salmon", "sea green",
                     "sienna", "slate blue", "spring green",
                     "steel blue", "tan", "thistle", "turquoise",
                     "violet", "violet red", "wheat",
                     "yellow green"};
*/

char *colorname[] = {"green4", "green3", "green2", "chartreuse2",
                     "OliveDrab2", "DarkOliveGreen2",
                     "SpringGreen3", "SpringGreen2",
                     "SeaGreen2", "DarkSeaGreen2", "aquamarine2",
                     "SlateGray2", "LightSteelBlue2",
                     "LightSkyBlue2", "LightBlue2",
                     "LightCyan2", "PaleTurquoise2", "CadetBlue2",
                     "turquoise2", "cyan2", "cyan3",
                     "SkyBlue2", "DeepSkyBlue2", "SteelBlue2",
                     "DodgerBlue2", "RoyalBlue2",
                     "RoyalBlue1", "royal blue",
                     "blue1", "blue2",
                     "medium blue", "midnight blue", "navy", "blue4",
                     "dark slate blue", "purple3", "purple2", "purple1",
                     "MediumPurple2", "MediumPurple3",
                     "DarkOrchid2", "DarkOrchid3",
                     "red4", "red3", "DeepPink3",
                     "maroon3", "magenta3", "maroon2", "magenta2",
                     "DeepPink2", "OrangeRed3", "red2", "red", "orange red",
                     "DarkOrange2", "chocolate2", "tan2", "DarkGoldenRod2",
                     "goldenrod2", "gold2", "yellow3", "yellow2",
                     "LightGoldenrod2", "khaki2"};



/* This section is matrix support for 3D graphics. */

struct vec_t {
  showmereal x, y, z;
};

struct int_t {
  int x, y, z;
};

typedef showmereal matrix_t[3][3];
typedef showmereal vector_t[3];

matrix_t viewmatrix; /* The current viewing transformation matrix */
showmereal xcenter, ycenter, zcenter;

void three_D_rot_matrix_x(matrix_t matrix,
                          showmereal theta)
{
  matrix[0][0] = 1.0;  matrix[0][1] = 0.0;         matrix[0][2] = 0.0;
  matrix[1][0] = 0.0;  matrix[1][1] = cos(theta);  matrix[1][2] = - sin(theta);
  matrix[2][0] = 0.0;  matrix[2][1] = sin(theta);  matrix[2][2] = cos(theta);
}

void three_D_rot_matrix_y(matrix_t matrix,
                          showmereal theta)
{
  matrix[0][0] = cos(theta);    matrix[0][1] = 0.0;  matrix[0][2] = sin(theta);
  matrix[1][0] = 0.0;           matrix[1][1] = 1.0;  matrix[1][2] = 0.0;
  matrix[2][0] = - sin(theta);  matrix[2][1] = 0.0;  matrix[2][2] = cos(theta);
}


void three_D_rot_matrix_z(matrix_t matrix,
                          showmereal theta)
{
  matrix[0][0] = cos(theta);  matrix[0][1] = - sin(theta);  matrix[0][2] = 0.0;
  matrix[1][0] = sin(theta);  matrix[1][1] = cos(theta);    matrix[1][2] = 0.0;
  matrix[2][0] = 0.0;         matrix[2][1] = 0.0;           matrix[2][2] = 1.0;
}

void mult_matmat(matrix_t inmatrix1,
                 matrix_t inmatrix2,
                 matrix_t outmatrix)
{
  showmereal
    a1 = inmatrix1[0][0], a2 = inmatrix1[0][1], a3 = inmatrix1[0][2],
    a4 = inmatrix1[1][0], a5 = inmatrix1[1][1], a6 = inmatrix1[1][2],
    a7 = inmatrix1[2][0], a8 = inmatrix1[2][1], a9 = inmatrix1[2][2];
  showmereal
    b1 = inmatrix2[0][0], b2 = inmatrix2[0][1], b3 = inmatrix2[0][2],
    b4 = inmatrix2[1][0], b5 = inmatrix2[1][1], b6 = inmatrix2[1][2],
    b7 = inmatrix2[2][0], b8 = inmatrix2[2][1], b9 = inmatrix2[2][2];

  outmatrix[0][0] = b1 * a1 + b4 * a2 + b7 * a3;
  outmatrix[1][0] = b1 * a4 + b4 * a5 + b7 * a6;
  outmatrix[2][0] = b1 * a7 + b4 * a8 + b7 * a9;

  outmatrix[0][1] = b2 * a1 + b5 * a2 + b8 * a3;
  outmatrix[1][1] = b2 * a4 + b5 * a5 + b8 * a6;
  outmatrix[2][1] = b2 * a7 + b5 * a8 + b8 * a9;

  outmatrix[0][2] = b3 * a1 + b6 * a2 + b9 * a3;
  outmatrix[1][2] = b3 * a4 + b6 * a5 + b9 * a6;
  outmatrix[2][2] = b3 * a7 + b6 * a8 + b9 * a9;
}

void mult_matvec(matrix_t inmatrix,
                 vector_t invector,
                 vector_t outvector)
{
  showmereal
    a1 = inmatrix[0][0], a2 = inmatrix[0][1], a3 = inmatrix[0][2],
    a4 = inmatrix[1][0], a5 = inmatrix[1][1], a6 = inmatrix[1][2],
    a7 = inmatrix[2][0], a8 = inmatrix[2][1], a9 = inmatrix[2][2];
  showmereal b1 = invector[0], b2 = invector[1], b3 = invector[2];

  outvector[0] = a1 * b1 + a2 * b2 + a3 * b3;
  outvector[1] = a4 * b1 + a5 * b2 + a6 * b3;
  outvector[2] = a7 * b1 + a8 * b2 + a9 * b3;
}

void identitymatrix(matrix_t matrix)
{
  matrix[0][0] = 1.0;  matrix[0][1] = 0.0;  matrix[0][2] = 0.0;
  matrix[1][0] = 0.0;  matrix[1][1] = 1.0;  matrix[1][2] = 0.0;
  matrix[2][0] = 0.0;  matrix[2][1] = 0.0;  matrix[2][2] = 1.0;
}

/* This section supports 3D perspective projection. */

showmereal Camera_Twist = 0.0;    /* Amount to twist about the viewing axis. */

/*  Calculate the distance according to the field of view */
/*#define FOV (130.0 * DEG2RAD)*/
/*static showmereal d = 1.0/(2.0*tan(FOV/2.0));*/

showmereal perspdistance;
showmereal perspfactor = 1.5;

/*
 *  PerspectiveProj:
 *     Take a point in (the camera's) 3-space and map it to (World) x-y space
 *     using LookFrom, LookAt, FOV,  and Oroll(about the viewing axis).
 */

void perspectiveproj(vector_t CAMcoord,
                     struct vec_t *World)
{
  showmereal viewz;
  /* Translate the Camera Point to the Origin first. */
  viewz = CAMcoord[2] + perspdistance;

  if (perspective) {
    World->x = CAMcoord[0] / viewz;
    World->y = CAMcoord[1] / viewz;
    World->z = 0.0;
  } else {
    World->x = CAMcoord[0];
    World->y = CAMcoord[1];
    World->z = CAMcoord[2];
  }
}

/* End graphics projection support */

/*****************************************************************************/
/*                                                                           */
/*  syntax()   Print a list of command line switches.                        */
/*                                                                           */
/*****************************************************************************/

void syntax()
{
  printf("showme [-bfw_Qh] input_file\n");
  printf("    -b  Black and white PostScript (default is color).\n");
  printf("    -f  Fill triangles of partitioned mesh with color.\n");
  printf("    -w  Set line width to some specified number.\n");
  printf("    -Q  Quiet:  No terminal output except errors.\n");
  printf("    -h  Help:  Detailed instructions for Show Me.\n");
  exit(0);
}

/*****************************************************************************/
/*                                                                           */
/*  info()   Print out complete instructions.                                */
/*                                                                           */
/*****************************************************************************/

void info()
{
  printf("Show Me\n");
  printf("A Display Program for Meshes and More.\n");
  printf("Version 1.61\n\n");
  printf("Copyright 1996, 1998 <NAME>\n");
  printf("965 Sutter Street #815 / San Francisco, California  94109-6082\n");
  printf("Bugs/comments to <EMAIL>\n");
  printf(
"Created as part of the Quake project (tools for earthquake simulation).\n");
  printf(
"Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.\n");
  printf("There is no warranty whatsoever.  Use at your own risk.\n");
#ifdef SINGLE
  printf("This executable is compiled for single precision arithmetic.\n\n\n");
#else
  printf("This executable is compiled for double precision arithmetic.\n\n\n");
#endif
  printf(
"Show Me graphically displays the contents of geometric files, especially\n");
  printf(
"those generated by Triangle, my two-dimensional quality mesh generator and\n"
);
  printf(
"Delaunay triangulator.  Show Me can also write images in PostScript form.\n");
  printf(
"Show Me is also useful for checking the consistency of the files you create\n"
);
  printf(
"as input to Triangle; Show Me does these checks more thoroughly than\n");
  printf("Triangle does.  The command syntax is:\n\n");
  printf("showme [-bfw_Qh] input_file\n\n");
  printf(
"The underscore indicates that a number should follow the -w switch.\n");
  printf(
"input_file may be one of several types of file.  It must have extension\n");
  printf(
".node, .poly, .ele, .edge, .part, or .adj.  If no extension is provided,\n");
  printf(
"Show Me will assume the extension .ele.  A .node file represents a set of\n");
  printf(
"points; a .poly file represents a Planar Straight Line Graph; an .ele file\n"
);
  printf(
"(coupled with a .node file) represents the elements of a mesh or the\n");
  printf(
"triangles of a triangulation; an .edge file (coupled with a .node file)\n");
  printf(
"represents a set of edges; a .part file specifies a partition of a mesh;\n");
  printf(
"and a .adj file represents the adjacency graph defined by a partition.\n");
  printf("\n");
  printf("Command Line Switches:\n");
  printf("\n");
  printf(
"    -b  Makes all PostScript output black and white.  If this switch is not\n"
);
  printf(
"        selected, color PostScript is used for partitioned meshes and\n");
  printf("        adjacency graphs (.part and .adj files).\n");
  printf(
"    -f  On color displays and in color PostScript, displays partitioned\n");
  printf(
"        meshes by filling triangles with color, rather than by coloring the\n"
);
  printf(
"        edges.  This switch will result in a clearer picture if all\n");
  printf(
"        triangles are reasonably large, and a less clear picture if small\n");
  printf(
"        triangles are present.  (There is also a button to toggle this\n");
  printf("        behavior.)\n");
  printf(
"    -w  Followed by an integer, specifies the line width used in all\n");
  printf(
"        images.  (There are also buttons to change the line width.)\n");
  printf(
"    -Q  Quiet:  Suppresses all explanation of what Show Me is doing, unless\n"
);
  printf("        an error occurs.\n");
  printf("    -h  Help:  Displays these instructions.\n");
  printf("\n");
  printf("Controls:\n");
  printf("\n");
  printf(
"  To zoom in on an image, point at the location where you want a closer\n");
  printf(
"  look, and click the left mouse button.  To zoom out, click the right\n");
  printf(
"  mouse button.  In either case, the point you click on will be centered in\n"
);
  printf(
"  the window.  If you want to know the coordinates of a point, click the\n");
  printf(
"  middle mouse button; the coordinates will be printed on the terminal you\n"
);
  printf("  invoked Show Me from.\n\n");
  printf(
"  If you resize the window, the image will grow or shrink to match.\n");
  printf("\n");
  printf(
"  There is a panel of control buttons at the bottom of the Show Me window:\n"
);
  printf("\n");
  printf("  Quit:  Shuts down Show Me.\n");
  printf("  <, >, ^, v:  Moves the image in the indicated direction.\n");
  printf(
"  Reset: Unzooms and centers the image in the window.  When you switch from\n"
);
  printf(
"    one image to another, the viewing region does not change, so you may\n");
  printf(
"    need to reset the new image to make it fully visible.  This often is\n");
  printf(
"    the case when switching between Delaunay triangulations and their\n");
  printf(
"    corresponding Voronoi diagrams, as Voronoi vertices can be far from the\n"
);
  printf("    initial point set.\n");
  printf(
"  Width+, -:  Increases or decreases the width of all lines and points.\n");
  printf(
"  Exp, +, -:  These buttons appear only when you are viewing a partitioned\n"
);
  printf(
"    mesh (.part file).  `Exp' toggles between an exploded and non-exploded\n"
);
  printf(
"    image of the mesh.  The non-exploded image will not show the partition\n"
);
  printf(
"    on a black and white monitor.  `+' and `-' allow you to adjust the\n");
  printf(
"    spacing between pieces of the mesh to better distinguish them.\n");
  printf(
"  Fill:  This button appears only when you are viewing a partitioned mesh\n");
  printf(
"    (.part file).  It toggles between color-filled triangles and colored\n");
  printf(
"    edges (as the -f switch does).  Filled triangles look better when all\n");
  printf(
"    triangles are reasonably large; colored edges look better when there\n");
  printf("    are very small triangles present.\n");
  printf(
"  PS:  Creates a PostScript file containing the image you are viewing.  If\n"
);
  printf(
"    the -b switch is selected, all PostScript output will be black and\n");
  printf(
"    white; otherwise, .part.ps and .adj.ps files will be color, independent\n"
);
  printf(
"    of whether you are using a color monitor.  Normally the output will\n");
  printf(
"    preserve the properties of the image you see on the screen, including\n");
  printf(
"    zoom and line width; however, if black and white output is selected (-b\n"
);
  printf(
"    switch), partitioned meshes will always be drawn exploded.  The output\n"
);
  printf(
"    file name depends on the image being viewed.  If you want several\n");
  printf(
"    different snapshots (zooming in on different parts) of the same object,\n"
);
  printf(
"    you'll have to rename each file after Show Me creates it so that it\n");
  printf("    isn't overwritten by the next snapshot.\n");
  printf(
"  EPS:  Creates an encapsulated PostScript file, suitable for inclusion in\n"
);
  printf(
"    documents.  Otherwise, this button is just like the PS button.  (The\n");
  printf(
"    only difference is that .eps files lack a `showpage' command at the\n");
  printf("    end.)\n\n");
  printf(
"  There are two nearly-identical rows of buttons that load different images\n"
);
  printf("  from disk.  Each row contains the following buttons:\n\n");
  printf("  node:  Loads a .node file.\n");
  printf(
"  poly:  Loads a .poly file (and possibly an associated .node file).\n");
  printf("  ele:  Loads an .ele file (and associated .node file).\n");
  printf("  edge:  Loads an .edge file (and associated .node file).\n");
  printf(
"  part:  Loads a .part file (and associated .node and .ele files).\n");
  printf(
"  adj:  Loads an .adj file (and associated .node, .ele, and .part files).\n");
  printf("  voro:  Loads a .v.node and .v.edge file for a Voronoi diagram.\n");
  printf("\n");
  printf(
"  Each row represents a different iteration number of the geometry files.\n");
  printf(
"  For a full explanation of iteration numbers, read the instructions for\n");
  printf(
"  Triangle.  Briefly, iteration numbers are used to allow a user to easily\n"
);
  printf(
"  represent a sequence of related triangulations.  Iteration numbers are\n");
  printf(
"  used in the names of geometry files; for instance, mymesh.3.ele is a\n");
  printf(
"  triangle file with iteration number three, and mymesh.ele has an implicit\n"
);
  printf("  iteration number of zero.\n\n");
  printf(
"  The control buttons at the right end of each row display the two\n");
  printf(
"  iterations currently under view.  These buttons can be clicked to\n");
  printf(
"  increase or decrease the iteration numbers, and thus conveniently view\n");
  printf("  a sequence of meshes.\n\n");
  printf(
"  Show Me keeps each file in memory after loading it, but you can force\n");
  printf(
"  Show Me to reread a set of files (for one iteration number) by reclicking\n"
);
  printf(
"  the button that corresponds to the current image.  This is convenient if\n"
);
  printf("  you have changed a geometry file.\n\n");
  printf("File Formats:\n\n");
  printf(
"  All files may contain comments prefixed by the character '#'.  Points,\n");
  printf(
"  segments, holes, triangles, edges, and subdomains must be numbered\n");
  printf(
"  consecutively, starting from either 1 or 0.  Whichever you choose, all\n");
  printf(
"  input files must be consistent (for any single iteration number); if the\n"
);
  printf(
"  nodes are numbered from 1, so must be all other objects.  Show Me\n");
  printf(
"  automatically detects your choice while reading a .node (or .poly) file.\n"
);
  printf("  Examples of these file formats are given below.\n\n");
  printf("  .node files:\n");
  printf(
"    First line:  <# of points> <dimension (must be 2)> <# of attributes>\n");
  printf(
"                                           <# of boundary markers (0 or 1)>\n"
);
  printf(
"    Remaining lines:  <point #> <x> <y> [attributes] [boundary marker]\n");
  printf("\n");
  printf(
"    The attributes, which are typically floating-point values of physical\n");
  printf(
"    quantities (such as mass or conductivity) associated with the nodes of\n"
);
  printf(
"    a finite element mesh, are ignored by Show Me.  Show Me also ignores\n");
  printf(
"    boundary markers.  See the instructions for Triangle to find out what\n");
  printf("    attributes and boundary markers are.\n\n");
  printf("  .poly files:\n");
  printf(
"    First line:  <# of points> <dimension (must be 2)> <# of attributes>\n");
  printf(
"                                           <# of boundary markers (0 or 1)>\n"
);
  printf(
"    Following lines:  <point #> <x> <y> [attributes] [boundary marker]\n");
  printf("    One line:  <# of segments> <# of boundary markers (0 or 1)>\n");
  printf(
"    Following lines:  <segment #> <endpoint> <endpoint> [boundary marker]\n");
  printf("    One line:  <# of holes>\n");
  printf("    Following lines:  <hole #> <x> <y>\n");
  printf("    [Optional additional lines that are ignored]\n\n");
  printf(
"    A .poly file represents a Planar Straight Line Graph (PSLG), an idea\n");
  printf(
"    familiar to computational geometers.  By definition, a PSLG is just a\n");
  printf(
"    list of points and edges.  A .poly file also contains some additional\n");
  printf("    information.\n\n");
  printf(
"    The first section lists all the points, and is identical to the format\n"
);
  printf(
"    of .node files.  <# of points> may be set to zero to indicate that the\n"
);
  printf(
"    points are listed in a separate .node file; .poly files produced by\n");
  printf(
"    Triangle always have this format.  When Show Me reads such a file, it\n");
  printf("    also reads the corresponding .node file.\n\n");
  printf(
"    The second section lists the segments.  Segments are edges whose\n");
  printf(
"    presence in a triangulation produced from the PSLG is enforced.  Each\n");
  printf(
"    segment is specified by listing the indices of its two endpoints.  This\n"
);
  printf(
"    means that its endpoints must be included in the point list.  Each\n");
  printf(
"    segment, like each point, may have a boundary marker, which is ignored\n"
);
  printf("    by Show Me.\n\n");
  printf(
"    The third section lists holes and concavities that are desired in any\n");
  printf(
"    triangulation generated from the PSLG.  Holes are specified by\n");
  printf("    identifying a point inside each hole.\n\n");
  printf("  .ele files:\n");
  printf(
"    First line:  <# of triangles> <points per triangle> <# of attributes>\n");
  printf(
"    Remaining lines:  <triangle #> <point> <point> <point> ... [attributes]\n"
);
  printf("\n");
  printf(
"    Points are indices into the corresponding .node file.  Show Me ignores\n"
);
  printf(
"    all but the first three points of each triangle; these should be the\n");
  printf(
"    corners listed in counterclockwise order around the triangle.  The\n");
  printf("    attributes are ignored by Show Me.\n\n");
  printf("  .edge files:\n");
  printf("    First line:  <# of edges> <# of boundary markers (0 or 1)>\n");
  printf(
"    Following lines:  <edge #> <endpoint> <endpoint> [boundary marker]\n");
  printf("\n");
  printf(
"    Endpoints are indices into the corresponding .node file.  The boundary\n"
);
  printf("    markers are ignored by Show Me.\n\n");
  printf(
"    In Voronoi diagrams, one also finds a special kind of edge that is an\n");
  printf(
"    infinite ray with only one endpoint.  For these edges, a different\n");
  printf("    format is used:\n\n");
  printf("        <edge #> <endpoint> -1 <direction x> <direction y>\n\n");
  printf(
"    The `direction' is a floating-point vector that indicates the direction\n"
);
  printf("    of the infinite ray.\n\n");
  printf("  .part files:\n");
  printf("    First line:  <# of triangles> <# of subdomains>\n");
  printf("    Remaining lines:  <triangle #> <subdomain #>\n\n");
  printf(
"    The set of triangles is partitioned by a .part file; each triangle is\n");
  printf("    mapped to a subdomain.\n\n");
  printf("  .adj files:\n");
  printf("    First line:  <# of subdomains>\n");
  printf("    Remaining lines:  <adjacency matrix entry>\n\n");
  printf(
"    An .adj file represents adjacencies between subdomains (presumably\n");
  printf("    computed by a partitioner).  The first line is followed by\n");
  printf(
"    (subdomains X subdomains) lines, each containing one entry of the\n");
  printf(
"    adjacency matrix.  A nonzero entry indicates that two subdomains are\n");
  printf("    adjacent (share a point).\n\n");
  printf("Example:\n\n");
  printf(
"  Here is a sample file `box.poly' describing a square with a square hole:\n"
);
  printf("\n");
  printf(
"    # A box with eight points in 2D, no attributes, no boundary marker.\n");
  printf("    8 2 0 0\n");
  printf("    # Outer box has these vertices:\n");
  printf("     1   0 0\n");
  printf("     2   0 3\n");
  printf("     3   3 0\n");
  printf("     4   3 3\n");
  printf("    # Inner square has these vertices:\n");
  printf("     5   1 1\n");
  printf("     6   1 2\n");
  printf("     7   2 1\n");
  printf("     8   2 2\n");
  printf("    # Five segments without boundary markers.\n");
  printf("    5 0\n");
  printf("     1   1 2          # Left side of outer box.\n");
  printf("     2   5 7          # Segments 2 through 5 enclose the hole.\n");
  printf("     3   7 8\n");
  printf("     4   8 6\n");
  printf("     5   6 5\n");
  printf("    # One hole in the middle of the inner square.\n");
  printf("    1\n");
  printf("     1   1.5 1.5\n\n");
  printf(
"  After this PSLG is triangulated by Triangle, the resulting triangulation\n"
);
  printf(
"  consists of a .node and .ele file.  Here is the former, `box.1.node',\n");
  printf("  which duplicates the points of the PSLG:\n\n");
  printf("    8  2  0  0\n");
  printf("       1    0  0\n");
  printf("       2    0  3\n");
  printf("       3    3  0\n");
  printf("       4    3  3\n");
  printf("       5    1  1\n");
  printf("       6    1  2\n");
  printf("       7    2  1\n");
  printf("       8    2  2\n");
  printf("    # Generated by triangle -pcBev box\n");
  printf("\n");
  printf("  Here is the triangulation file, `box.1.ele'.\n");
  printf("\n");
  printf("    8  3  0\n");
  printf("       1       1     5     6\n");
  printf("       2       5     1     3\n");
  printf("       3       2     6     8\n");
  printf("       4       6     2     1\n");
  printf("       5       7     3     4\n");
  printf("       6       3     7     5\n");
  printf("       7       8     4     2\n");
  printf("       8       4     8     7\n");
  printf("    # Generated by triangle -pcBev box\n\n");
  printf("  Here is the edge file for the triangulation, `box.1.edge'.\n\n");
  printf("    16  0\n");
  printf("       1   1  5\n");
  printf("       2   5  6\n");
  printf("       3   6  1\n");
  printf("       4   1  3\n");
  printf("       5   3  5\n");
  printf("       6   2  6\n");
  printf("       7   6  8\n");
  printf("       8   8  2\n");
  printf("       9   2  1\n");
  printf("      10   7  3\n");
  printf("      11   3  4\n");
  printf("      12   4  7\n");
  printf("      13   7  5\n");
  printf("      14   8  4\n");
  printf("      15   4  2\n");
  printf("      16   8  7\n");
  printf("    # Generated by triangle -pcBev box\n");
  printf("\n");
  printf(
"  Here's a file `box.1.part' that partitions the mesh into four subdomains.\n"
);
  printf("\n");
  printf("    8  4\n");
  printf("       1    3\n");
  printf("       2    3\n");
  printf("       3    4\n");
  printf("       4    4\n");
  printf("       5    1\n");
  printf("       6    1\n");
  printf("       7    2\n");
  printf("       8    2\n");
  printf("    # Generated by slice -s4 box.1\n\n");
  printf(
"  Here's a file `box.1.adj' that represents the resulting adjacencies.\n");
  printf("\n");
  printf("    4\n");
  printf("      9\n");
  printf("      2\n");
  printf("      2\n");
  printf("      0\n");
  printf("      2\n");
  printf("      9\n");
  printf("      0\n");
  printf("      2\n");
  printf("      2\n");
  printf("      0\n");
  printf("      9\n");
  printf("      2\n");
  printf("      0\n");
  printf("      2\n");
  printf("      2\n");
  printf("      9\n");
  printf("\n");
  printf("Display Speed:\n");
  printf("\n");
  printf(
"  It is worthwhile to note that .edge files typically plot and print twice\n"
);
  printf(
"  as quickly as .ele files, because .ele files cause each internal edge to\n"
);
  printf(
"  be drawn twice.  For the same reason, PostScript files created from edge\n"
);
  printf("  sets are smaller than those created from triangulations.\n\n");
  printf("Show Me on the Web:\n\n");
  printf(
"  To see an illustrated, updated version of these instructions, check out\n");
  printf("\n");
  printf("    http://www.cs.cmu.edu/~quake/showme.html\n");
  printf("\n");
  printf("A Brief Plea:\n");
  printf("\n");
  printf(
"  If you use Show Me (or Triangle), and especially if you use it to\n");
  printf(
"  accomplish real work, I would like very much to hear from you.  A short\n");
  printf(
"  letter or email (to <EMAIL>) describing how you use Show Me\n");
  printf(
"  (and its sister programs) will mean a lot to me.  The more people I know\n"
);
  printf(
"  are using my programs, the more easily I can justify spending time on\n");
  printf(
"  improvements, which in turn will benefit you.  Also, I can put you\n");
  printf(
"  on a list to receive email whenever new versions are available.\n");
  printf("\n");
  printf(
"  If you use a PostScript file generated by Show Me in a publication,\n");
  printf("  please include an acknowledgment as well.\n\n");
  exit(0);
}

void setfilenames(char *filename,
                  int lowermeshnumber)
{
  char numberstring[100];
  int i;

  for (i = 0; i < 2; i++) {
    strcpy(nodefilename[i], filename);
    strcpy(polyfilename[i], filename);
    strcpy(elefilename[i], filename);
    strcpy(edgefilename[i], filename);
    strcpy(partfilename[i], filename);
    strcpy(adjfilename[i], filename);
    strcpy(vnodefilename[i], filename);
    strcpy(vedgefilename[i], filename);
    strcpy(datafilename[i], filename);

    if (lowermeshnumber + i > 0) {
      sprintf(numberstring, ".%d", lowermeshnumber + i);
      strcat(nodefilename[i], numberstring);
      strcat(polyfilename[i], numberstring);
      strcat(elefilename[i], numberstring);
      strcat(edgefilename[i], numberstring);
      strcat(partfilename[i], numberstring);
      strcat(adjfilename[i], numberstring);
      strcat(vnodefilename[i], numberstring);
      strcat(vedgefilename[i], numberstring);
      strcat(datafilename[i], numberstring);
    }

    strcat(nodefilename[i], ".node");
    strcat(polyfilename[i], ".poly");
    strcat(elefilename[i], ".ele");
    strcat(edgefilename[i], ".edge");
    strcat(partfilename[i], ".part");
    strcat(adjfilename[i], ".adj");
    strcat(vnodefilename[i], ".v.node");
    strcat(vedgefilename[i], ".v.edge");
    strcat(datafilename[i], ".data");
  }
}

void parsecommandline(int argc,
                      char **argv)
{
  int increment;
  int meshnumber;
  int i, j;

  quiet = 0;
  fillelem = 0;
  line_width = 1;
  bw_ps = 0;
  start_image = ELE;
  randomseed = 1;
  filename[0] = '\0';
  for (i = 1; i < argc; i++) {
    if (argv[i][0] == '-') {
      for (j = 1; argv[i][j] != '\0'; j++) {
        if (argv[i][j] == 'f') {
          fillelem = 1;
	}
        if (argv[i][j] == 'w') {
          if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '9')) {
            line_width = 0;
            while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
              j++;
              line_width = line_width * 10 + (int) (argv[i][j] - '0');
            }
            if (line_width > 100) {
              printf("Error:  Line width cannot exceed 100.\n");
              line_width = 1;
	    }
	  }
	}
        if (argv[i][j] == 'b') {
          bw_ps = 1;
	}
        if (argv[i][j] == 'Q') {
          quiet = 1;
	}
        if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
            (argv[i][j] == '?')) {
          info();
	}
      }
    } else {
      /* Any command-line parameter not starting with "-" is assumed to be */
      /*   a file name.                                                    */
      strncpy(filename, argv[i], FILENAMESIZE - 1);
      filename[FILENAMESIZE - 1] = '\0';
    }
  }

  if (filename[0] == '\0') {
    /* No file name specified; print a summary of the command line switches. */
    syntax();
  }

  /* Remove the filename extension (if any) and use it to infer what type */
  /*   of file should be displayed.                                       */
  if (!strcmp(&filename[strlen(filename) - 5], ".node")) {
    filename[strlen(filename) - 5] = '\0';
    start_image = NODE;
  }
  if (!strcmp(&filename[strlen(filename) - 5], ".poly")) {
    filename[strlen(filename) - 5] = '\0';
    start_image = POLY;
  }
  if (!strcmp(&filename[strlen(filename) - 4], ".ele")) {
    filename[strlen(filename) - 4] = '\0';
    start_image = ELE;
  }
  if (!strcmp(&filename[strlen(filename) - 5], ".edge")) {
    filename[strlen(filename) - 5] = '\0';
    start_image = EDGE;
  }
  if (!strcmp(&filename[strlen(filename) - 5], ".part")) {
    filename[strlen(filename) - 5] = '\0';
    start_image = PART;
  }
  if (!strcmp(&filename[strlen(filename) - 4], ".adj")) {
    filename[strlen(filename) - 4] = '\0';
    start_image = ADJ;
  }
  if (!strcmp(&filename[strlen(filename) - 5], ".data")) {
    filename[strlen(filename) - 5] = '\0';
    start_image = DATA;
  }

  /* Check the input filename for an iteration number. */
  increment = 0;
  /* Find the last period in the filename. */
  j = 1;
  while (filename[j] != '\0') {
    if ((filename[j] == '.') && (filename[j + 1] != '\0')) {
      increment = j + 1;
    }
    j++;
  }
  /* The iteration number is zero by default, unless there's an iteration */
  /*   number in the filename.                                            */
  meshnumber = 0;
  if (increment > 0) {
    /* Read the iteration number from the end of the filename. */
    j = increment;
    do {
      if ((filename[j] >= '0') && (filename[j] <= '9')) {
        meshnumber = meshnumber * 10 + (int) (filename[j] - '0');
      } else {
        /* Oops, not a digit; this isn't an iteration number after all. */
        increment = 0;
        meshnumber = 0;
        break;
      }
      j++;
    } while (filename[j] != '\0');
  }
  if (increment > 0) {
    /* Lop off the iteration number. */
    filename[increment - 1] = '\0';
  }

  if (meshnumber == 0) {
    /* Initially, load the mesh with no iteration number (corresponding to */
    /*   number zero), and also provide buttons for iteration one.         */
    start_inc = 0;
    loweriteration = 0;
  } else {
    /* Initially, load the mesh with the specified iteration number, and */
    /*   also provide buttons for the previous iteration (one less).     */
    start_inc = 1;
    loweriteration = meshnumber - 1;
  }

  /* Set the filenames for the two iterations on the buttons. */
  setfilenames(filename, loweriteration);
}

/********* Geometric primitives begin here                           *********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  Robust geometric predicates using adaptive precision floating-point      */
/*  arithmetic                                                               */
/*                                                                           */
/*  The adaptive exact arithmetic geometric predicates implemented herein    */
/*  are described in detail in my paper, "Adaptive Precision Floating-Point  */
/*  Arithmetic and Fast Robust Geometric Predicates."  See the header for a  */
/*  full citation.                                                           */
/*                                                                           */
/*****************************************************************************/

/*  Which of the following two methods of finding the absolute values is     */
/*  fastest is compiler-dependent.  A few compilers can inline and optimize  */
/*  the fabs() call; but most will incur the overhead of a function call,    */
/*  which is disastrously slow.  A faster way on IEEE machines might be to   */
/*  mask the appropriate bit.                                                */

#define Absolute(a)  ((a) >= 0.0 ? (a) : -(a))
/* #define Absolute(a)  fabs(a) */

/*  Many of the operations are broken up into two pieces--a main part that   */
/*  performs an approximate operation, and a "tail" that computes the        */
/*  roundoff error of that operation.                                        */
/*                                                                           */
/*  The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(),   */
/*  Split(), and Two_Product() are all implemented as described in the       */
/*  reference.  Each of these macros requires certain variables to be        */
/*  defined in the calling routine.  The variables `bvirt', `c', `abig',     */
/*  `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because    */
/*  they store the result of an operation that may incur roundoff error.     */
/*  The input parameter `x' (or the highest numbered `x_' parameter) must    */
/*  also be declared `INEXACT'.                                              */

#define Fast_Two_Sum_Tail(a, b, x, y) \
  bvirt = x - a; \
  y = b - bvirt

#define Fast_Two_Sum(a, b, x, y) \
  x = (showmereal) (a + b); \
  Fast_Two_Sum_Tail(a, b, x, y)

#define Two_Sum_Tail(a, b, x, y) \
  bvirt = (showmereal) (x - a); \
  avirt = x - bvirt; \
  bround = b - bvirt; \
  around = a - avirt; \
  y = around + bround

#define Two_Sum(a, b, x, y) \
  x = (showmereal) (a + b); \
  Two_Sum_Tail(a, b, x, y)

#define Two_Diff_Tail(a, b, x, y) \
  bvirt = (showmereal) (a - x); \
  avirt = x + bvirt; \
  bround = bvirt - b; \
  around = a - avirt; \
  y = around + bround

#define Two_Diff(a, b, x, y) \
  x = (showmereal) (a - b); \
  Two_Diff_Tail(a, b, x, y)

#define Split(a, ahi, alo) \
  c = (showmereal) (splitter * a); \
  abig = (showmereal) (c - a); \
  ahi = c - abig; \
  alo = a - ahi

#define Two_Product_Tail(a, b, x, y) \
  Split(a, ahi, alo); \
  Split(b, bhi, blo); \
  err1 = x - (ahi * bhi); \
  err2 = err1 - (alo * bhi); \
  err3 = err2 - (ahi * blo); \
  y = (alo * blo) - err3

#define Two_Product(a, b, x, y) \
  x = (showmereal) (a * b); \
  Two_Product_Tail(a, b, x, y)

#define Two_Product_Presplit(a, b, bhi, blo, x, y) \
  x = (showmereal) (a * b); \
  Split(a, ahi, alo); \
  err1 = x - (ahi * bhi); \
  err2 = err1 - (alo * bhi); \
  err3 = err2 - (ahi * blo); \
  y = (alo * blo) - err3

#define Square_Tail(a, x, y) \
  Split(a, ahi, alo); \
  err1 = x - (ahi * ahi); \
  err3 = err1 - ((ahi + ahi) * alo); \
  y = (alo * alo) - err3

#define Square(a, x, y) \
  x = (showmereal) (a * a); \
  Square_Tail(a, x, y)

#define Two_One_Sum(a1, a0, b, x2, x1, x0) \
  Two_Sum(a0, b , _i, x0); \
  Two_Sum(a1, _i, x2, x1)

#define Two_One_Diff(a1, a0, b, x2, x1, x0) \
  Two_Diff(a0, b , _i, x0); \
  Two_Sum( a1, _i, x2, x1)

#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \
  Two_One_Sum(a1, a0, b0, _j, _0, x0); \
  Two_One_Sum(_j, _0, b1, x3, x2, x1)

#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \
  Two_One_Diff(a1, a0, b0, _j, _0, x0); \
  Two_One_Diff(_j, _0, b1, x3, x2, x1)

#define Four_One_Sum(a3, a2, a1, a0, b, x4, x3, x2, x1, x0) \
  Two_One_Sum(a1, a0, b , _j, x1, x0); \
  Two_One_Sum(a3, a2, _j, x4, x3, x2)

#define Four_Two_Sum(a3, a2, a1, a0, b1, b0, x5, x4, x3, x2, x1, x0) \
  Four_One_Sum(a3, a2, a1, a0, b0, _k, _2, _1, _0, x0); \
  Four_One_Sum(_k, _2, _1, _0, b1, x5, x4, x3, x2, x1)

#define Four_Four_Sum(a3, a2, a1, a0, b4, b3, b1, b0, x7, x6, x5, x4, x3, x2, \
                      x1, x0) \
  Four_Two_Sum(a3, a2, a1, a0, b1, b0, _l, _2, _1, _0, x1, x0); \
  Four_Two_Sum(_l, _2, _1, _0, b4, b3, x7, x6, x5, x4, x3, x2)

#define Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b, x8, x7, x6, x5, x4, \
                      x3, x2, x1, x0) \
  Four_One_Sum(a3, a2, a1, a0, b , _j, x3, x2, x1, x0); \
  Four_One_Sum(a7, a6, a5, a4, _j, x8, x7, x6, x5, x4)

#define Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, x9, x8, x7, \
                      x6, x5, x4, x3, x2, x1, x0) \
  Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b0, _k, _6, _5, _4, _3, _2, \
                _1, _0, x0); \
  Eight_One_Sum(_k, _6, _5, _4, _3, _2, _1, _0, b1, x9, x8, x7, x6, x5, x4, \
                x3, x2, x1)

#define Eight_Four_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b4, b3, b1, b0, x11, \
                       x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0) \
  Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, _l, _6, _5, _4, _3, \
                _2, _1, _0, x1, x0); \
  Eight_Two_Sum(_l, _6, _5, _4, _3, _2, _1, _0, b4, b3, x11, x10, x9, x8, \
                x7, x6, x5, x4, x3, x2)

#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \
  Split(b, bhi, blo); \
  Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \
  Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \
  Two_Sum(_i, _0, _k, x1); \
  Fast_Two_Sum(_j, _k, x3, x2)

/*****************************************************************************/
/*                                                                           */
/*  primitivesinit()   Initialize the variables used for exact arithmetic.   */
/*                                                                           */
/*  `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in   */
/*  floating-point arithmetic.  `epsilon' bounds the relative roundoff       */
/*  error.  It is used for floating-point error analysis.                    */
/*                                                                           */
/*  `splitter' is used to split floating-point numbers into two half-        */
/*  length significands for exact multiplication.                            */
/*                                                                           */
/*  I imagine that a highly optimizing compiler might be too smart for its   */
/*  own good, and somehow cause this routine to fail, if it pretends that    */
/*  floating-point arithmetic is too much like real arithmetic.              */
/*                                                                           */
/*  Don't change this routine unless you really understand it.               */
/*                                                                           */
/*****************************************************************************/

void primitivesinit()
{
  showmereal half;
  showmereal check, lastcheck;
  int every_other;
#ifdef LINUX
  int cword;
#endif /* LINUX */

#ifdef CPU86
#ifdef SINGLE
  _control87(_PC_24, _MCW_PC); /* Set FPU control word for single precision. */
#else /* not SINGLE */
  _control87(_PC_53, _MCW_PC); /* Set FPU control word for double precision. */
#endif /* not SINGLE */
#endif /* CPU86 */
#ifdef LINUX
#ifdef SINGLE
  /*  cword = 4223; */
  cword = 4210;                 /* set FPU control word for single precision */
#else /* not SINGLE */
  /*  cword = 4735; */
  cword = 4722;                 /* set FPU control word for double precision */
#endif /* not SINGLE */
  _FPU_SETCW(cword);
#endif /* LINUX */

  every_other = 1;
  half = 0.5;
  epsilon = 1.0;
  splitter = 1.0;
  check = 1.0;
  /* Repeatedly divide `epsilon' by two until it is too small to add to      */
  /*   one without causing roundoff.  (Also check if the sum is equal to     */
  /*   the previous sum, for machines that round up instead of using exact   */
  /*   rounding.  Not that these routines will work on such machines.)       */
  do {
    lastcheck = check;
    epsilon *= half;
    if (every_other) {
      splitter *= 2.0;
    }
    every_other = !every_other;
    check = 1.0 + epsilon;
  } while ((check != 1.0) && (check != lastcheck));
  splitter += 1.0;

  /* Error bounds for orientation test. */
  resulterrbound = (3.0 + 8.0 * epsilon) * epsilon;
  o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon;
  o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon;
  o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon;
}

/*****************************************************************************/
/*                                                                           */
/*  fast_expansion_sum_zeroelim()   Sum two expansions, eliminating zero     */
/*                                  components from the output expansion.    */
/*                                                                           */
/*  Sets h = e + f.  See my Robust Predicates paper for details.             */
/*                                                                           */
/*  h cannot be e or f.                                                      */
/*                                                                           */
/*  If round-to-even is used (as with IEEE 754), maintains the strongly      */
/*  nonoverlapping property.  (That is, if e is strongly nonoverlapping, h   */
/*  will be also.)  Does NOT maintain the nonoverlapping or nonadjacent      */
/*  properties.                                                              */
/*                                                                           */
/*****************************************************************************/

int fast_expansion_sum_zeroelim(int elen,
                                showmereal *e,
                                int flen,
                                showmereal *f,
                                showmereal *h)
{
  showmereal Q;
  INEXACT showmereal Qnew;
  INEXACT showmereal hh;
  INEXACT showmereal bvirt;
  showmereal avirt, bround, around;
  int eindex, findex, hindex;
  showmereal enow, fnow;

  enow = e[0];
  fnow = f[0];
  eindex = findex = 0;
  if ((fnow > enow) == (fnow > -enow)) {
    Q = enow;
    enow = e[++eindex];
  } else {
    Q = fnow;
    fnow = f[++findex];
  }
  hindex = 0;
  if ((eindex < elen) && (findex < flen)) {
    if ((fnow > enow) == (fnow > -enow)) {
      Fast_Two_Sum(enow, Q, Qnew, hh);
      enow = e[++eindex];
    } else {
      Fast_Two_Sum(fnow, Q, Qnew, hh);
      fnow = f[++findex];
    }
    Q = Qnew;
    if (hh != 0.0) {
      h[hindex++] = hh;
    }
    while ((eindex < elen) && (findex < flen)) {
      if ((fnow > enow) == (fnow > -enow)) {
        Two_Sum(Q, enow, Qnew, hh);
        enow = e[++eindex];
      } else {
        Two_Sum(Q, fnow, Qnew, hh);
        fnow = f[++findex];
      }
      Q = Qnew;
      if (hh != 0.0) {
        h[hindex++] = hh;
      }
    }
  }
  while (eindex < elen) {
    Two_Sum(Q, enow, Qnew, hh);
    enow = e[++eindex];
    Q = Qnew;
    if (hh != 0.0) {
      h[hindex++] = hh;
    }
  }
  while (findex < flen) {
    Two_Sum(Q, fnow, Qnew, hh);
    fnow = f[++findex];
    Q = Qnew;
    if (hh != 0.0) {
      h[hindex++] = hh;
    }
  }
  if ((Q != 0.0) || (hindex == 0)) {
    h[hindex++] = Q;
  }
  return hindex;
}

/*****************************************************************************/
/*                                                                           */
/*  scale_expansion_zeroelim()   Multiply an expansion by a scalar,          */
/*                               eliminating zero components from the        */
/*                               output expansion.                           */
/*                                                                           */
/*  Sets h = be.  See my Robust Predicates paper for details.                */
/*                                                                           */
/*  e and h cannot be the same.                                              */
/*                                                                           */
/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
/*  with IEEE 754), maintains the strongly nonoverlapping and nonadjacent    */
/*  properties as well.  (That is, if e has one of these properties, so      */
/*  will h.)                                                                 */
/*                                                                           */
/*****************************************************************************/

int scale_expansion_zeroelim(int elen,
                             showmereal *e,
                             showmereal b,
                             showmereal *h)
{
  INEXACT showmereal Q, sum;
  showmereal hh;
  INEXACT showmereal product1;
  showmereal product0;
  int eindex, hindex;
  showmereal enow;
  INEXACT showmereal bvirt;
  showmereal avirt, bround, around;
  INEXACT showmereal c;
  INEXACT showmereal abig;
  showmereal ahi, alo, bhi, blo;
  showmereal err1, err2, err3;

  Split(b, bhi, blo);
  Two_Product_Presplit(e[0], b, bhi, blo, Q, hh);
  hindex = 0;
  if (hh != 0) {
    h[hindex++] = hh;
  }
  for (eindex = 1; eindex < elen; eindex++) {
    enow = e[eindex];
    Two_Product_Presplit(enow, b, bhi, blo, product1, product0);
    Two_Sum(Q, product0, sum, hh);
    if (hh != 0) {
      h[hindex++] = hh;
    }
    Fast_Two_Sum(product1, sum, Q, hh);
    if (hh != 0) {
      h[hindex++] = hh;
    }
  }
  if ((Q != 0.0) || (hindex == 0)) {
    h[hindex++] = Q;
  }
  return hindex;
}

/*****************************************************************************/
/*                                                                           */
/*  estimate()   Produce a one-word estimate of an expansion's value.        */
/*                                                                           */
/*  See my Robust Predicates paper for details.                              */
/*                                                                           */
/*****************************************************************************/

showmereal estimate(int elen,
                    showmereal *e)
{
  showmereal Q;
  int eindex;

  Q = e[0];
  for (eindex = 1; eindex < elen; eindex++) {
    Q += e[eindex];
  }
  return Q;
}

/*****************************************************************************/
/*                                                                           */
/*  orient3d()   Return a positive value if the point pd lies below the      */
/*               plane passing through pa, pb, and pc; "below" is defined so */
/*               that pa, pb, and pc appear in counterclockwise order when   */
/*               viewed from above the plane.  Returns a negative value if   */
/*               pd lies above the plane.  Returns zero if the points are    */
/*               coplanar.  The result is also a rough approximation of six  */
/*               times the signed volume of the tetrahedron defined by the   */
/*               four points.                                                */
/*                                                                           */
/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
/*  result returned is the determinant of a matrix.  This determinant is     */
/*  computed adaptively, in the sense that exact arithmetic is used only to  */
/*  the degree it is needed to ensure that the returned value has the        */
/*  correct sign.  Hence, this function is usually quite fast, but will run  */
/*  more slowly when the input points are coplanar or nearly so.             */
/*                                                                           */
/*  See my Robust Predicates paper for details.                              */
/*                                                                           */
/*****************************************************************************/

showmereal orient3dadapt(showmereal *pa,
                       showmereal *pb,
                       showmereal *pc,
                       showmereal *pd,
                       showmereal permanent)
{
  INEXACT showmereal adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz;
  showmereal det, errbound;

  INEXACT showmereal bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
  showmereal bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
  showmereal bc[4], ca[4], ab[4];
  INEXACT showmereal bc3, ca3, ab3;
  showmereal adet[8], bdet[8], cdet[8];
  int alen, blen, clen;
  showmereal abdet[16];
  int ablen;
  showmereal *finnow, *finother, *finswap;
  showmereal fin1[192], fin2[192];
  int finlength;

  showmereal adxtail, bdxtail, cdxtail;
  showmereal adytail, bdytail, cdytail;
  showmereal adztail, bdztail, cdztail;
  INEXACT showmereal at_blarge, at_clarge;
  INEXACT showmereal bt_clarge, bt_alarge;
  INEXACT showmereal ct_alarge, ct_blarge;
  showmereal at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4];
  int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen;
  INEXACT showmereal bdxt_cdy1, cdxt_bdy1, cdxt_ady1;
  INEXACT showmereal adxt_cdy1, adxt_bdy1, bdxt_ady1;
  showmereal bdxt_cdy0, cdxt_bdy0, cdxt_ady0;
  showmereal adxt_cdy0, adxt_bdy0, bdxt_ady0;
  INEXACT showmereal bdyt_cdx1, cdyt_bdx1, cdyt_adx1;
  INEXACT showmereal adyt_cdx1, adyt_bdx1, bdyt_adx1;
  showmereal bdyt_cdx0, cdyt_bdx0, cdyt_adx0;
  showmereal adyt_cdx0, adyt_bdx0, bdyt_adx0;
  showmereal bct[8], cat[8], abt[8];
  int bctlen, catlen, abtlen;
  INEXACT showmereal bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1;
  INEXACT showmereal adxt_cdyt1, adxt_bdyt1, bdxt_adyt1;
  showmereal bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0;
  showmereal adxt_cdyt0, adxt_bdyt0, bdxt_adyt0;
  showmereal u[4], v[12], w[16];
  INEXACT showmereal u3;
  int vlength, wlength;
  showmereal negate;

  INEXACT showmereal bvirt;
  showmereal avirt, bround, around;
  INEXACT showmereal c;
  INEXACT showmereal abig;
  showmereal ahi, alo, bhi, blo;
  showmereal err1, err2, err3;
  INEXACT showmereal _i, _j, _k;
  showmereal _0;

  adx = (showmereal) (pa[0] - pd[0]);
  bdx = (showmereal) (pb[0] - pd[0]);
  cdx = (showmereal) (pc[0] - pd[0]);
  ady = (showmereal) (pa[1] - pd[1]);
  bdy = (showmereal) (pb[1] - pd[1]);
  cdy = (showmereal) (pc[1] - pd[1]);
  adz = (showmereal) (pa[2] - pd[2]);
  bdz = (showmereal) (pb[2] - pd[2]);
  cdz = (showmereal) (pc[2] - pd[2]);

  Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
  Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
  Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
  bc[3] = bc3;
  alen = scale_expansion_zeroelim(4, bc, adz, adet);

  Two_Product(cdx, ady, cdxady1, cdxady0);
  Two_Product(adx, cdy, adxcdy1, adxcdy0);
  Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
  ca[3] = ca3;
  blen = scale_expansion_zeroelim(4, ca, bdz, bdet);

  Two_Product(adx, bdy, adxbdy1, adxbdy0);
  Two_Product(bdx, ady, bdxady1, bdxady0);
  Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
  ab[3] = ab3;
  clen = scale_expansion_zeroelim(4, ab, cdz, cdet);

  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
  finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);

  det = estimate(finlength, fin1);
  errbound = o3derrboundB * permanent;
  if ((det >= errbound) || (-det >= errbound)) {
    return det;
  }

  Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
  Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
  Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
  Two_Diff_Tail(pa[1], pd[1], ady, adytail);
  Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
  Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
  Two_Diff_Tail(pa[2], pd[2], adz, adztail);
  Two_Diff_Tail(pb[2], pd[2], bdz, bdztail);
  Two_Diff_Tail(pc[2], pd[2], cdz, cdztail);

  if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) &&
      (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0) &&
      (adztail == 0.0) && (bdztail == 0.0) && (cdztail == 0.0)) {
    return det;
  }

  errbound = o3derrboundC * permanent + resulterrbound * Absolute(det);
  det += (adz * ((bdx * cdytail + cdy * bdxtail)
                 - (bdy * cdxtail + cdx * bdytail))
          + adztail * (bdx * cdy - bdy * cdx))
       + (bdz * ((cdx * adytail + ady * cdxtail)
                 - (cdy * adxtail + adx * cdytail))
          + bdztail * (cdx * ady - cdy * adx))
       + (cdz * ((adx * bdytail + bdy * adxtail)
                 - (ady * bdxtail + bdx * adytail))
          + cdztail * (adx * bdy - ady * bdx));
  if ((det >= errbound) || (-det >= errbound)) {
    return det;
  }

  finnow = fin1;
  finother = fin2;

  if (adxtail == 0.0) {
    if (adytail == 0.0) {
      at_b[0] = 0.0;
      at_blen = 1;
      at_c[0] = 0.0;
      at_clen = 1;
    } else {
      negate = -adytail;
      Two_Product(negate, bdx, at_blarge, at_b[0]);
      at_b[1] = at_blarge;
      at_blen = 2;
      Two_Product(adytail, cdx, at_clarge, at_c[0]);
      at_c[1] = at_clarge;
      at_clen = 2;
    }
  } else {
    if (adytail == 0.0) {
      Two_Product(adxtail, bdy, at_blarge, at_b[0]);
      at_b[1] = at_blarge;
      at_blen = 2;
      negate = -adxtail;
      Two_Product(negate, cdy, at_clarge, at_c[0]);
      at_c[1] = at_clarge;
      at_clen = 2;
    } else {
      Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0);
      Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0);
      Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0,
                   at_blarge, at_b[2], at_b[1], at_b[0]);
      at_b[3] = at_blarge;
      at_blen = 4;
      Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0);
      Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0);
      Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0,
                   at_clarge, at_c[2], at_c[1], at_c[0]);
      at_c[3] = at_clarge;
      at_clen = 4;
    }
  }
  if (bdxtail == 0.0) {
    if (bdytail == 0.0) {
      bt_c[0] = 0.0;
      bt_clen = 1;
      bt_a[0] = 0.0;
      bt_alen = 1;
    } else {
      negate = -bdytail;
      Two_Product(negate, cdx, bt_clarge, bt_c[0]);
      bt_c[1] = bt_clarge;
      bt_clen = 2;
      Two_Product(bdytail, adx, bt_alarge, bt_a[0]);
      bt_a[1] = bt_alarge;
      bt_alen = 2;
    }
  } else {
    if (bdytail == 0.0) {
      Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]);
      bt_c[1] = bt_clarge;
      bt_clen = 2;
      negate = -bdxtail;
      Two_Product(negate, ady, bt_alarge, bt_a[0]);
      bt_a[1] = bt_alarge;
      bt_alen = 2;
    } else {
      Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0);
      Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0);
      Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0,
                   bt_clarge, bt_c[2], bt_c[1], bt_c[0]);
      bt_c[3] = bt_clarge;
      bt_clen = 4;
      Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0);
      Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0);
      Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0,
                  bt_alarge, bt_a[2], bt_a[1], bt_a[0]);
      bt_a[3] = bt_alarge;
      bt_alen = 4;
    }
  }
  if (cdxtail == 0.0) {
    if (cdytail == 0.0) {
      ct_a[0] = 0.0;
      ct_alen = 1;
      ct_b[0] = 0.0;
      ct_blen = 1;
    } else {
      negate = -cdytail;
      Two_Product(negate, adx, ct_alarge, ct_a[0]);
      ct_a[1] = ct_alarge;
      ct_alen = 2;
      Two_Product(cdytail, bdx, ct_blarge, ct_b[0]);
      ct_b[1] = ct_blarge;
      ct_blen = 2;
    }
  } else {
    if (cdytail == 0.0) {
      Two_Product(cdxtail, ady, ct_alarge, ct_a[0]);
      ct_a[1] = ct_alarge;
      ct_alen = 2;
      negate = -cdxtail;
      Two_Product(negate, bdy, ct_blarge, ct_b[0]);
      ct_b[1] = ct_blarge;
      ct_blen = 2;
    } else {
      Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0);
      Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0);
      Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0,
                   ct_alarge, ct_a[2], ct_a[1], ct_a[0]);
      ct_a[3] = ct_alarge;
      ct_alen = 4;
      Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0);
      Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0);
      Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0,
                   ct_blarge, ct_b[2], ct_b[1], ct_b[0]);
      ct_b[3] = ct_blarge;
      ct_blen = 4;
    }
  }

  bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct);
  wlength = scale_expansion_zeroelim(bctlen, bct, adz, w);
  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                          finother);
  finswap = finnow; finnow = finother; finother = finswap;

  catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat);
  wlength = scale_expansion_zeroelim(catlen, cat, bdz, w);
  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                          finother);
  finswap = finnow; finnow = finother; finother = finswap;

  abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt);
  wlength = scale_expansion_zeroelim(abtlen, abt, cdz, w);
  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                          finother);
  finswap = finnow; finnow = finother; finother = finswap;

  if (adztail != 0.0) {
    vlength = scale_expansion_zeroelim(4, bc, adztail, v);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }
  if (bdztail != 0.0) {
    vlength = scale_expansion_zeroelim(4, ca, bdztail, v);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }
  if (cdztail != 0.0) {
    vlength = scale_expansion_zeroelim(4, ab, cdztail, v);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }

  if (adxtail != 0.0) {
    if (bdytail != 0.0) {
      Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0);
      Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (cdztail != 0.0) {
        Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
    if (cdytail != 0.0) {
      negate = -adxtail;
      Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0);
      Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (bdztail != 0.0) {
        Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
  }
  if (bdxtail != 0.0) {
    if (cdytail != 0.0) {
      Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0);
      Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (adztail != 0.0) {
        Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
    if (adytail != 0.0) {
      negate = -bdxtail;
      Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0);
      Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (cdztail != 0.0) {
        Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
  }
  if (cdxtail != 0.0) {
    if (adytail != 0.0) {
      Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0);
      Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (bdztail != 0.0) {
        Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
    if (bdytail != 0.0) {
      negate = -cdxtail;
      Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0);
      Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (adztail != 0.0) {
        Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
  }

  if (adztail != 0.0) {
    wlength = scale_expansion_zeroelim(bctlen, bct, adztail, w);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }
  if (bdztail != 0.0) {
    wlength = scale_expansion_zeroelim(catlen, cat, bdztail, w);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }
  if (cdztail != 0.0) {
    wlength = scale_expansion_zeroelim(abtlen, abt, cdztail, w);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }

  return finnow[finlength - 1];
}

showmereal orient3d(showmereal *pa,
                    showmereal *pb,
                    showmereal *pc,
                    showmereal *pd)
{
  showmereal adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz;
  showmereal bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
  showmereal det;
  showmereal permanent, errbound;

  adx = pa[0] - pd[0];
  bdx = pb[0] - pd[0];
  cdx = pc[0] - pd[0];
  ady = pa[1] - pd[1];
  bdy = pb[1] - pd[1];
  cdy = pc[1] - pd[1];
  adz = pa[2] - pd[2];
  bdz = pb[2] - pd[2];
  cdz = pc[2] - pd[2];

  bdxcdy = bdx * cdy;
  cdxbdy = cdx * bdy;

  cdxady = cdx * ady;
  adxcdy = adx * cdy;

  adxbdy = adx * bdy;
  bdxady = bdx * ady;

  det = adz * (bdxcdy - cdxbdy) 
      + bdz * (cdxady - adxcdy)
      + cdz * (adxbdy - bdxady);

  permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz)
            + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz)
            + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz);
  errbound = o3derrboundA * permanent;
  if ((det > errbound) || (-det > errbound)) {
    return det;
  }

  return orient3dadapt(pa, pb, pc, pd, permanent);
}

/**                                                                         **/
/**                                                                         **/
/********* Geometric primitives end here                             *********/

void free_inc(int inc)
{
  if (loaded[inc][NODE]) {
    free(nodeptr[inc]);
  }

  if (loaded[inc][POLY]) {
    if (polynodes[inc] > 0) {
      free(polynodeptr[inc]);
    }
    free(polysegptr[inc]);
    free(polyholeptr[inc]);
  }

  if (loaded[inc][ELE]) {
    free(eleptr[inc]);
    if (nodedim[inc] == 3) {
      free(tetraptr);
    }
  }

  if (loaded[inc][EDGE]) {
    free(edgeptr[inc]);
    free(normptr[inc]);
  }

  if (loaded[inc][PART]) {
    free(partition[inc]);
    free(subdomcenter[inc]);
    free(subdomshift[inc]);
  }

  if (loaded[inc][ADJ]) {
    free(adjptr[inc]);
  }

  if (loaded[inc][VORO]) {
    free(vnodeptr[inc]);
    free(vedgeptr[inc]);
    free(vnormptr[inc]);
  }

  if (loaded[inc][DATA]) {
    free(dataptr[inc]);
  }
}

void move_inc(int inc)
{
  int i;

  free_inc(1 - inc);

  for (i = 0; i < IMAGE_TYPES; i++) {
    loaded[1 - inc][i] = loaded[inc][i];
    loaded[inc][i] = 0;
    xlo[1 - inc][i] = xlo[inc][i];
    ylo[1 - inc][i] = ylo[inc][i];
    zlo[1 - inc][i] = zlo[inc][i];
    xhi[1 - inc][i] = xhi[inc][i];
    yhi[1 - inc][i] = yhi[inc][i];
    zhi[1 - inc][i] = zhi[inc][i];
  }

  nodes[1 - inc] = nodes[inc];
  nodedim[1 - inc] = nodedim[inc];
  nodeptr[1 - inc] = nodeptr[inc];
  polynodes[1 - inc] = polynodes[inc];
  polydim[1 - inc] = polydim[inc];
  polyedges[1 - inc] = polyedges[inc];
  polyholes[1 - inc] = polyholes[inc];
  polynodeptr[1 - inc] = polynodeptr[inc];
  polysegptr[1 - inc] = polysegptr[inc];
  polyholeptr[1 - inc] = polyholeptr[inc];
  elems[1 - inc] = elems[inc];
  elecorners[1 - inc] = elecorners[inc];
  eleptr[1 - inc] = eleptr[inc];
  edges[1 - inc] = edges[inc];
  edgeptr[1 - inc] = edgeptr[inc];
  normptr[1 - inc] = normptr[inc];
  subdomains[1 - inc] = subdomains[inc];
  partition[1 - inc] = partition[inc];
  subdomcenter[1 - inc] = subdomcenter[inc];
  subdomshift[1 - inc] = subdomshift[inc];
  adjsubdomains[1 - inc] = adjsubdomains[inc];
  adjptr[1 - inc] = adjptr[inc];
  vnodes[1 - inc] = vnodes[inc];
  vnodedim[1 - inc] = vnodedim[inc];
  vnodeptr[1 - inc] = vnodeptr[inc];
  vedges[1 - inc] = vedges[inc];
  vedgeptr[1 - inc] = vedgeptr[inc];
  vnormptr[1 - inc] = vnormptr[inc];
  datavalues[1 - inc] = datavalues[inc];
  datadim[1 - inc] = datadim[inc];
  dataptr[1 - inc] = dataptr[inc];
  firstnumber[1 - inc] = firstnumber[inc];
  firstnumber[inc] = -1;
}

void unload_inc(int inc)
{
  int i;

  current_image = NOTHING;
  for (i = 0; i < IMAGE_TYPES; i++) {
    loaded[inc][i] = 0;
    firstnumber[inc] = -1;
  }
}

void showme_init()
{
  int template, forward, reverse;
  int i;

  primitivesinit();
  current_image = NOTHING;
  current_inc = 0;
  explosion = STARTEXPLOSION;
  identitymatrix(viewmatrix);
  unload_inc(0);
  unload_inc(1);
  for (i = 0; i < MAXCOLORS; i++) {
    template = MAXCOLORS - 1;
    forward = i;
    reverse = 0;
    while (template != 0) {
      reverse = (reverse << 1) | (forward & 1);
      forward >>= 1;
      template >>= 1;
    }
    bitreverse[i] = reverse;
  }
}

void matchfaces(showmereal *nodeptr,
                showmelong numnodes,
                showmelong numelems,
                int dim,
                showmelong *eleptr,
                struct tetra **tetraptr)
{
  showmelong *node2nodelem;
  showmelong *nodelem2nodelem;
  showmelong thisnode, thisnodelem, thiselem;
  int thiscorner;
  showmelong thisnode1, thisnode2;
  int farcorner;
  showmelong matchnodelem, matchelem;
  int matchcorner;
  showmelong matchnode1, matchnode2, matchnode3;
  showmelong firsttet;

  /* Create array of tetrahedron adjacencies. */
  *tetraptr = (struct tetra *) malloc((numelems + 1) * sizeof(struct tetra));

  /* Short-lived arrays used to fill in the above array.  They maintain for */
  /*   each vertex a linked list of tetrahedra adjoining it.                */
  node2nodelem = (showmelong *) malloc((numnodes + 1) * sizeof(showmelong));
  nodelem2nodelem = (showmelong *)
                    malloc((numelems + 1) * 4 * sizeof(showmelong));

  /* All lists are initially empty. */
  for (thisnode = 1; thisnode <= numnodes; thisnode++) {
    node2nodelem[thisnode] = 0;
  }

  /* Initially, nothing is linked. */
  for (thiselem = 1; thiselem <= numelems; thiselem++)  {
    (*tetraptr)[thiselem].invisible = 0;
    for (thiscorner = 0; thiscorner < 4; thiscorner++) {
      (*tetraptr)[thiselem].neighbor[thiscorner] = 0;
    }
  }

  /* For each vertex, form a linked list of the tetrahedra that adjoin it. */
  for (thisnodelem = 4; thisnodelem < 4 * numelems + 4; thisnodelem++) {
    thisnode = eleptr[thisnodelem];
    nodelem2nodelem[thisnodelem] = node2nodelem[thisnode];
    node2nodelem[thisnode] = thisnodelem;
  }

  /* Loop through the vertices. */
  for (thisnode = 1; thisnode <= numnodes; thisnode++) {
    /* Loop through the tetrahedra adjoining this vertex. */
    thisnodelem = node2nodelem[thisnode];
    while (thisnodelem != 0) {
      /* The next tetrahedron (and joining corner) in the linked list. */
      thiselem = thisnodelem >> 2;
      thiscorner = (int) (thisnodelem & 3);
      /* Loop through the other corners (besides `thisnode') of the        */
      /*   tetrahedron for which the opposite tetrahedron isn't yet known. */
      for (farcorner = 0; farcorner < 4; farcorner++) {
        if ((farcorner != thiscorner) &&
            ((*tetraptr)[thiselem].neighbor[farcorner] == 0)) {
          /* Identify the other two corners. */
          thisnode1 = 3 - (farcorner & 1) - (thiscorner & 2);
          thisnode2 = 6 - farcorner - thiscorner - thisnode1;
          thisnode1 = eleptr[thiselem * 4 + thisnode1];
          thisnode2 = eleptr[thiselem * 4 + thisnode2];
          /* Loop through the remaining tetrahedra in the linked list,    */
          /*   looking for one that shares the face (thisnode, thisnode1, */
          /*   thisnode2).                                                */
          matchnodelem = nodelem2nodelem[thisnodelem];
          while (matchnodelem != 0) {
            /* The next tetrahedron (and joining corner) in the linked list. */
            matchelem = matchnodelem >> 2;
            matchcorner = (int) (matchnodelem & 3);
            /* Identify the other three corners. */
            matchnode1 = eleptr[matchelem * 4 + ((matchcorner + 1) & 3)];
            matchnode2 = eleptr[matchelem * 4 + ((matchcorner + 2) & 3)];
            matchnode3 = eleptr[matchelem * 4 + ((matchcorner + 3) & 3)];
            /* Check each of the three faces of the later tetrahedron that */
            /*   adjoin `thisnode' to see if any of them adjoins the face  */
            /*   opposite `farcorner' in the earlier tetrahedron.          */
            if (((thisnode1 == matchnode2) && (thisnode2 == matchnode3)) ||
                ((thisnode1 == matchnode3) && (thisnode2 == matchnode2))) {
              /* Glue the two tetrahedra together opposite `matchnode1'. */
              (*tetraptr)[thiselem].neighbor[farcorner] =
                matchelem * 4 + ((matchcorner + 1) & 3);
              (*tetraptr)[matchelem].neighbor[(matchcorner + 1) & 3] =
                thiselem * 4 + farcorner;
            }
            if (((thisnode1 == matchnode3) && (thisnode2 == matchnode1)) ||
                ((thisnode1 == matchnode1) && (thisnode2 == matchnode3))) {
              /* Glue the two tetrahedra together opposite `matchnode2'. */
              (*tetraptr)[thiselem].neighbor[farcorner] =
                matchelem * 4 + ((matchcorner + 2) & 3);
              (*tetraptr)[matchelem].neighbor[(matchcorner + 2) & 3] =
                thiselem * 4 + farcorner;
            }
            if (((thisnode1 == matchnode1) && (thisnode2 == matchnode2)) ||
                ((thisnode1 == matchnode2) && (thisnode2 == matchnode1))) {
              /* Glue the two tetrahedra together opposite `matchnode3'. */
              (*tetraptr)[thiselem].neighbor[farcorner] =
                matchelem * 4 + ((matchcorner + 3) & 3);
              (*tetraptr)[matchelem].neighbor[(matchcorner + 3) & 3] =
                thiselem * 4 + farcorner;
            }
            /* Find the next tetrahedron/corner in the linked list. */
            matchnodelem = nodelem2nodelem[matchnodelem];
          }
        }
      }
      /* Find the next tetrahedron/corner in the linked list. */
      thisnodelem = nodelem2nodelem[thisnodelem];
    }
  }

  /* Free the linked list arrays. */
  free(nodelem2nodelem);
  free(node2nodelem);

  /* Loop through the tetrahedra (in reverse order), creating a linked list */
  /*   of those that have at least one exposed (i.e. unshared) face.        */
  firsttet = 0;
  for (thiselem = numelems; thiselem > 0; thiselem--) {
    /* No tetrahedron is initially invisible. */
    (*tetraptr)[thiselem].invisible = 0;
    if (((*tetraptr)[thiselem].neighbor[0] <= 0) ||
        ((*tetraptr)[thiselem].neighbor[1] <= 0) ||
        ((*tetraptr)[thiselem].neighbor[2] <= 0) ||
        ((*tetraptr)[thiselem].neighbor[3] <= 0)) {
      /* Add this tetrahedron to the front of the linked list. */
      (*tetraptr)[thiselem].nexttet = firsttet;
      firsttet = thiselem;
    }
  }
  /* Remember the head of the linked list. */
  (*tetraptr)[0].nexttet = firsttet;
}

char *readline(char *string,
               FILE *infile,
               char *infilename)
{
  char *result;

  /* Search for something that looks like a number. */
  do {
    result = fgets(string, INPUTLINESIZE, infile);
    if (result == (char *) NULL) {
      printf("  Error:  Unexpected end of file in %s.\n", infilename);
      exit(1);
    }

    /* Skip anything that doesn't look like a number, a comment, */
    /*   or the end of a line.                                   */
    while ((*result != '\0') && (*result != '#') &&
           (*result != '.') && (*result != '+') && (*result != '-') &&
           ((*result < '0') || (*result > '9'))) {
      result++;
    }
  /* If it's a comment or end of line, read another line and try again. */
  } while ((*result == '#') || (*result == '\0'));

  return result;
}

char *findfield(char *string)
{
  char *result;

  result = string;
  /* Skip the current field.  Stop upon reaching whitespace. */
  while ((*result != '\0') && (*result != '#') &&
         (*result != ' ') && (*result != '\t')) {
    result++;
  }

  /* Now skip the whitespace and anything else that doesn't look like a */
  /*   number, a comment, or the end of a line.                         */
  while ((*result != '\0') && (*result != '#') &&
         (*result != '.') && (*result != '+') && (*result != '-') &&
         ((*result < '0') || (*result > '9'))) {
    result++;
  }

  /* Check for a comment (prefixed with `#'). */
  if (*result == '#') {
    *result = '\0';
  }

  return result;
}

int loadnodes(char *fname,
              int *firstnumber,
              showmelong *nodes,
              int *dim,
              showmereal **ptr,
              showmereal *xmin,
              showmereal *ymin,
              showmereal *zmin,
              showmereal *xmax,
              showmereal *ymax,
              showmereal *zmax)
{
  FILE *infile;
  char inputline[INPUTLINESIZE];
  char *stringptr;
  int extras;
  int nodemarks;
  showmelong nodenumber;
  showmelong i;
  int j;
  showmelong index;
  int smallerr;
  showmereal x, y, z;

  /* Set up a meaningful bounding box in case there's an error and no */
  /*   points get loaded.                                             */
  *xmin = *ymin = *zmin = 0.0;
  *xmax = *ymax = *zmax = 1.0;

  if (!quiet) {
    printf("Opening %s.\n", fname);
  }
  infile = fopen(fname, "r");
  if (infile == (FILE *) NULL) {
    printf("  Error:  Cannot access file %s.\n", fname);
    return 1;
  }

  /* Read and check number of points. */
  stringptr = readline(inputline, infile, fname);
  *nodes = (showmelong) strtol(stringptr, &stringptr, 0);
  if (*nodes < 3) {
    printf("  Error:  %s contains only %ld points.\n", fname, (long) *nodes);
    return 1;
  }

  /* Read and check dimensionality of points. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    *dim = 2;
  } else {
    *dim = (int) strtol(stringptr, &stringptr, 0);
  }
  if (*dim < 1) {
    printf("  Error:  %s has dimensionality %d.\n", fname, *dim);
    return 1;
  }
  if ((*dim < 2) || (*dim > 3)) {
    printf("  Error:  I only understand two and three-dimensional meshes.\n");
    return 1;
  }

  /* Read and check number of point attributes. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    extras = 0;
  } else {
    extras = (int) strtol(stringptr, &stringptr, 0);
  }
  if ((extras < 0) && !quiet) {
    printf("  Warning:  %s has negative value for number of attributes.\n",
           fname);
  }

  /* Read and check number of point markers. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    nodemarks = 0;
  } else {
    nodemarks = (int) strtol(stringptr, &stringptr, 0);
  }
  if (nodemarks < 0) {
    printf("  Warning:  %s has negative value for number of point markers.\n",
           fname);
  }
  if (nodemarks > 1) {
    printf(
   "  Warning:  %s has value greater than one for number of point markers.\n",
           fname);
  }

  /* Allocate space to store the points. */
  *ptr = (showmereal *) malloc((*nodes + 1) * *dim * sizeof(showmereal));
  if (*ptr == (showmereal *) NULL) {
    printf("  Error:  Out of memory.\n");
    return 1;
  }

  /* Read the points.  The coordinate index `index' starts at '*dim', */
  /*   because points are internally numbered from 1 (regardless of   */
  /*   how they're numbered in the file).                             */
  index = *dim;
  smallerr = 1;
  for (i = 0; i < *nodes; i++) {
    stringptr = readline(inputline, infile, fname);
    nodenumber = (showmelong) strtol(stringptr, &stringptr, 0);

    /* The point numbers are mostly ignored, except that the first one      */
    /*   tells us whether points are numbered from zero or one in the file. */
    if ((i == 0) && (*firstnumber == -1)) {
      if (nodenumber == 0) {
        *firstnumber = 0;
      } else {
        *firstnumber = 1;
      }
    }
    /* If points are not numbered consecutively, print a warning. */
    if ((nodenumber != *firstnumber + i) && (smallerr)) {
      printf("  Warning:  Points in %s are not numbered correctly\n", fname);
      printf("            (starting with point %ld).\n",
             (long) (*firstnumber + i));
      /* Don't print more minor errors after this. */
      smallerr = 0;
    }

    /* Read this point's coordinates. */
    for (j = 0; j < *dim; j++) {
      stringptr = findfield(stringptr);
      if (*stringptr == '\0') {
        printf("Error:  Point %ld is missing a coordinate in %s.\n",
               (long) (*firstnumber + i), fname);
        /* Free the memory for points and return an error indication. */
        free(*ptr);
        return 1;
      }
      /* Store the coordinate and advance the coordinate index. */
      (*ptr)[index++] = (showmereal) strtod(stringptr, &stringptr);
    }
  }

  fclose(infile);

  /* Use the first point's coordinates to initialize the bounding box. */
  index = *dim;
  *xmin = *xmax = (*ptr)[index];
  *ymin = *ymax = (*ptr)[index + 1];
  if (*dim == 3) {
    *zmin = *zmax = (*ptr)[index + 2];
  }
  /* Loop through the remaining points and update the bounding box. */
  for (i = 2; i <= *nodes; i++) {
    index += *dim;
    x = (*ptr)[index];
    y = (*ptr)[index + 1];
    if (x < *xmin) {
      *xmin = x;
    }
    if (y < *ymin) {
      *ymin = y;
    }
    if (x > *xmax) {
      *xmax = x;
    }
    if (y > *ymax) {
      *ymax = y;
    }
    if (*dim == 3) {
      z = (*ptr)[index + 2];
      if (z < *zmin) {
	*zmin = z;
      }
      if (z > *zmax) {
	*zmax = z;
      }
    }
  }

  /* Make sure the minima and maxima don't coincide. */
  if (*xmin == *xmax) {
    *xmin -= 0.5;
    *xmax += 0.5;
  }
  if (*ymin == *ymax) {
    *ymin -= 0.5;
    *ymax += 0.5;
  }
  if (*dim == 3) {
    if (*zmin == *zmax) {
      *zmin -= 0.5;
      *zmax += 0.5;
    }
  }

  return 0;
}

int loadpoly(int inc,
             char *fname,
             int *firstnumber,
             showmelong *pnodes,
             int *dim,
             showmelong *segments,
             showmelong *holes,
             showmereal **nodeptr,
             showmelong **segptr,
             showmereal **holeptr,
             showmereal *xmin,
             showmereal *ymin,
             showmereal *zmin,
             showmereal *xmax,
             showmereal *ymax,
             showmereal *zmax)
{
  FILE *infile;
  char inputline[INPUTLINESIZE];
  char *stringptr;
  int extras;
  int nodemarks;
  int segmentmarks;
  showmelong nodenumber, edgenumber, holenumber;
  showmelong maxnode;
  showmelong i;
  int j;
  showmelong index;
  int smallerr;
  showmereal x, y, z;

  if (!quiet) {
    printf("Opening %s.\n", fname);
  }
  infile = fopen(fname, "r");
  if (infile == (FILE *) NULL) {
    printf("  Error:  Cannot access file %s.\n", fname);
    return 1;
  }

  /* Read and check number of points. */
  stringptr = readline(inputline, infile, fname);
  *pnodes = (showmelong) strtol(stringptr, &stringptr, 0);
  if (*pnodes == 0) {
    /* The .poly file specifies zero nodes, which means that the nodes are */
    /*   stored in a separate .node file.  Make sure it's loaded.          */
    if (!loaded[inc][NODE]) {
      if (load_image(inc, NODE)) {
        /* The .node file is absent or broken; return an error indication. */
        return 1;
      }
    }

    /* Get number of nodes in the .node file. */
    maxnode = nodes[inc];
    /* This .poly file has the same bounding box as the .node file. */
    *xmin = xlo[inc][NODE];
    *ymin = ylo[inc][NODE];
    *zmin = zlo[inc][NODE];
    *xmax = xhi[inc][NODE];
    *ymax = yhi[inc][NODE];
    *zmax = zhi[inc][NODE];
  } else {
    if (*pnodes < 1) {
      printf("  Error:  %s contains %ld points.\n", fname, (long) *pnodes);
      return 1;
    }
    /* Get number of nodes in the .poly file. */
    maxnode = *pnodes;
    /* Set up a meaningful bounding box in case there's an error and no */
    /*   points get loaded.                                             */
    *xmin = *ymin = *zmin = 0.0;
    *xmax = *ymax = *zmax = 1.0;
  }

  /* Read and check dimensionality of points. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    *dim = 2;
  } else {
    *dim = (int) strtol(stringptr, &stringptr, 0);
  }
  if (*dim < 1) {
    printf("  Error:  %s has dimensionality %d.\n", fname, *dim);
    return 1;
  }
  if (*dim != 2) {
    printf("  Error:  I only understand two-dimensional .poly files.\n");
    return 1;
  }
  if ((*pnodes == 0) && (*dim != nodedim[inc])) {
    printf("  Error:  Dimensionality of .poly and .node files don't match.\n");
    return 1;
  }

  /* Read and check number of point attributes. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    extras = 0;
  } else {
    extras = (int) strtol(stringptr, &stringptr, 0);
  }
  if ((extras < 0) && !quiet) {
    printf("  Warning:  %s has negative value for number of attributes.\n",
           fname);
  }

  /* Read and check number of point markers. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    nodemarks = 0;
  } else {
    nodemarks = (int) strtol(stringptr, &stringptr, 0);
  }
  if (nodemarks < 0) {
    printf("  Warning:  %s has negative value for number of point markers.\n",
           fname);
  }
  if (nodemarks > 1) {
    printf("  Warning:  %s has value greater than one for number of point "
           "markers.\n", fname);
  }

  if (*pnodes > 0) {
    /* Allocate space to store the points. */
    *nodeptr = (showmereal *)
               malloc((*pnodes + 1) * *dim * sizeof(showmereal));
    if (*nodeptr == (showmereal *) NULL) {
      printf("  Error:  Out of memory.\n");
      return 1;
    }

    /* Read the points.  The coordinate index `index' starts at '*dim', */
    /*   because points are internally numbered from 1 (regardless of   */
    /*   how they're numbered in the file).                             */
    index = *dim;
    smallerr = 1;
    for (i = 0; i < *pnodes; i++) {
      stringptr = readline(inputline, infile, fname);
      nodenumber = (showmelong) strtol(stringptr, &stringptr, 0);

      /* The point numbers are mostly ignored, except that the first one */
      /*   tells us whether points are numbered from zero or one in the  */
      /*   file.                                                         */
      if ((i == 0) && (*firstnumber == -1)) {
        if (nodenumber == 0) {
          *firstnumber = 0;
        } else {
          *firstnumber = 1;
        }
      }
      /* If points are not numbered consecutively, print a warning. */
      if ((nodenumber != *firstnumber + i) && (smallerr)) {
        printf("  Warning:  Points in %s are not numbered correctly.\n",
               fname);
        printf("            (starting with point %ld).\n",
               (long) (*firstnumber + i));
        smallerr = 0;
      }

      /* Read this point's coordinates. */
      for (j = 0; j < *dim; j++) {
        stringptr = findfield(stringptr);
        if (*stringptr == '\0') {
          printf("Error:  Point %ld is missing a coordinate in %s.\n",
                 (long) (*firstnumber + i), fname);
          /* Free the memory for points and return an error indication. */
          free(*nodeptr);
          return 1;
        }
        /* Store the coordinate and advance the coordinate index. */
        (*nodeptr)[index++] = (showmereal) strtod(stringptr, &stringptr);
      }
    }
  }

  /* Read and check number of segments. */
  stringptr = readline(inputline, infile, fname);
  *segments = (showmelong) strtol(stringptr, &stringptr, 0);
  if (*segments < 0) {
    printf("  Error:  %s contains %ld segments.\n", fname, (long) *segments);
    /* Free the memory for points and return an error indication. */
    if (*pnodes > 0) {
      free(*nodeptr);
    }
    return 1;
  }

  /* Read and check number of segment markers. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    segmentmarks = 0;
  } else {
    segmentmarks = (int) strtol(stringptr, &stringptr, 0);
  }
  if (segmentmarks < 0) {
    printf("  Warning:  %s has negative value for number of segment "
           "markers.\n", fname);
  }
  if (segmentmarks > 1) {
    printf("  Warning:  %s has value greater than one for number of segment "
           "markers.\n", fname);
  }

  /* Allocate space to store the segments. */
  *segptr = (showmelong *) malloc(((*segments + 1) << 1) * sizeof(showmelong));
  if (*segptr == (showmelong *) NULL) {
    printf("  Error:  Out of memory.\n");
    /* Free the memory for points and return an error indication. */
    if (*pnodes > 0) {
      free(*nodeptr);
    }
    return 1;
  }

  /* Read the segments.  The corner index `index' starts at 2, because    */
  /*   segments are internally numbered from 1 (regardless of how they're */
  /*   numbered in the file).                                             */
  index = 2;
  smallerr = 1;
  for (i = *firstnumber; i < *firstnumber + *segments; i++) {
    stringptr = readline(inputline, infile, fname);
    edgenumber = (showmelong) strtol(stringptr, &stringptr, 0);

    /* If segments are not numbered as expected, print a warning. */
    if ((edgenumber != i) && (smallerr)) {
      printf("  Warning:  Segments in %s are not numbered correctly.\n",
             fname);
      printf("            (starting with segment %ld).\n", (long) i);
      /* Don't print more minor errors after this. */
      smallerr = 0;
    }

    /* Read the first segment endpoint; adjust it so the vertices are */
    /*   internally numbered from one.                                */
    stringptr = findfield(stringptr);
    if (*stringptr == '\0') {
      printf("Error:  Segment %ld is missing its endpoints in %s.\n",
             (long) i, fname);
      /* Free the memory for everything and return an error indication. */
      if (*pnodes > 0) {
        free(*nodeptr);
      }
      free(*segptr);
      return 1;
    }
    (*segptr)[index] = (showmelong) strtol(stringptr, &stringptr, 0) + 1 -
                       *firstnumber;

    /* Check if the first endpoint is valid. */
    if (((*segptr)[index] < 1) || ((*segptr)[index] > maxnode)) {
      printf("Error:  Segment %ld has invalid endpoint in %s.\n",
             (long) i, fname);
      return 1;
    }

    /* Read the second segment endpoint; adjust it so the vertices are */
    /*   internally numbered from one.                                 */
    stringptr = findfield(stringptr);
    if (*stringptr == '\0') {
      printf("Error:  Segment %ld is missing an endpoint in %s.\n",
             (long) i, fname);
      /* Free the memory for everything and return an error indication. */
      if (*pnodes > 0) {
        free(*nodeptr);
      }
      free(*segptr);
      return 1;
    }
    (*segptr)[index + 1] = (showmelong) strtol(stringptr, &stringptr, 0) + 1 -
                           *firstnumber;

    /* Check if the second endpoint is valid. */
    if (((*segptr)[index + 1] < 1) || ((*segptr)[index + 1] > maxnode)) {
      printf("Error:  Segment %ld has invalid endpoint in %s.\n",
             (long) i, fname);
      return 1;
    }

    index += 2;
  }

  /* Read and check number of holes. */
  stringptr = readline(inputline, infile, fname);
  *holes = (showmelong) strtol(stringptr, &stringptr, 0);
  if (*holes < 0) {
    printf("  Error:  %s contains %ld holes.\n", fname, (long) *holes);
    /* Free the memory for everything and return an error indication. */
    if (*pnodes > 0) {
      free(*nodeptr);
    }
    free(*segptr);
    return 1;
  }

  /* Allocate space to store the holes. */
  *holeptr = (showmereal *) malloc((*holes + 1) * *dim * sizeof(showmereal));
  if (*holeptr == (showmereal *) NULL) {
    printf("  Error:  Out of memory.\n");
    /* Free the memory for everything and return an error indication. */
    if (*pnodes > 0) {
      free(*nodeptr);
    }
    free(*segptr);
    return 1;
  }

  /* Read the holes.  The coordinate index `index' starts at '*dim', */
  /*   because holes are internally numbered from 1 (regardless of   */
  /*   how they're numbered in the file).                            */
  index = *dim;
  smallerr = 1;
  for (i = *firstnumber; i < *firstnumber + *holes; i++) {
    stringptr = readline(inputline, infile, fname);
    holenumber = (showmereal) strtol(stringptr, &stringptr, 0);

    /* If holes are not numbered as expected, print a warning. */
    if ((holenumber != i) && (smallerr)) {
      printf("  Warning:  Holes in %s are not numbered correctly.\n", fname);
      printf("            (starting with hole %ld).\n", (long) i);
      /* Don't print more minor errors after this. */
      smallerr = 0;
    }

    /* Read this hole's coordinates. */
    for (j = 0; j < *dim; j++) {
      stringptr = findfield(stringptr);
      if (*stringptr == '\0') {
        printf("Error:  Hole %ld is missing a coordinate in %s.\n",
               (long) i, fname);
        /* Free the memory for everything and return an error indication. */
        if (*pnodes > 0) {
          free(*nodeptr);
        }
        free(*segptr);
        free(*holeptr);
        return 1;
      }
        /* Store the coordinate and advance the coordinate index. */
      (*holeptr)[index++] = (showmereal) strtod(stringptr, &stringptr);
    }
  }

  fclose(infile);

  if (*pnodes > 0) {
    /* Use the first point's coordinates to initialize the bounding box. */
    index = *dim;
    *xmin = *xmax = (*nodeptr)[index];
    *ymin = *ymax = (*nodeptr)[index + 1];
    if (*dim == 2) {
      *zmin = 0.0;
      *zmax = 1.0;
    } else {
      *zmin = *zmax = (*nodeptr)[index + 2];
    }
    /* Loop through the remaining points and update the bounding box. */
    for (i = 2; i <= *pnodes; i++) {
      index += *dim;
      x = (*nodeptr)[index];
      y = (*nodeptr)[index + 1];
      if (x < *xmin) {
        *xmin = x;
      }
      if (y < *ymin) {
        *ymin = y;
      }
      if (x > *xmax) {
        *xmax = x;
      }
      if (y > *ymax) {
        *ymax = y;
      }
      if (*dim == 3) {
        z = (*nodeptr)[index + 2];
        if (z < *zmin) {
          *zmin = z;
        }
        if (z > *zmax) {
          *zmax = z;
        }
      }
    }
  }
  /* Loop through the holes and update the bounding box. */
  index = *dim;
  for (i = 1; i <= *holes; i++) {
    x = (*holeptr)[index];
    y = (*holeptr)[index + 1];
    if (x < *xmin) {
      *xmin = x;
    }
    if (y < *ymin) {
      *ymin = y;
    }
    if (x > *xmax) {
      *xmax = x;
    }
    if (y > *ymax) {
      *ymax = y;
    }
    if (*dim == 3) {
      z = (*holeptr)[index + 2];
      if (z < *zmin) {
        *zmin = z;
      }
      if (z > *zmax) {
        *zmax = z;
      }
    }
    index += *dim;
  }

  return 0;
}

int loadelems(char *fname,
              int dim,
              int firstnumber,
              showmelong nodes,
              showmereal *nodeptr,
              showmelong *elems,
              int *corners,
              showmelong **eleptr)
{
  FILE *infile;
  char inputline[INPUTLINESIZE];
  char *stringptr;
  showmelong extras;
  showmelong index;
  showmelong elemnumber;
  showmelong i, j;
  showmelong smallerr;
  showmelong swap;

  if (!quiet) {
    printf("Opening %s.\n", fname);
  }
  infile = fopen(fname, "r");
  if (infile == (FILE *) NULL) {
    printf("  Error:  Cannot access file %s.\n", fname);
    return 1;
  }

  /* Read and check number of elements. */
  stringptr = readline(inputline, infile, fname);
  *elems = (showmelong) strtol(stringptr, &stringptr, 0);
  if (*elems < 1) {
    printf("  Error:  %s contains %ld elements.\n", fname, (long) *elems);
    return 1;
  }

  /* Read and check points per element. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    *corners = dim + 1;
  } else {
    *corners = (int) strtol(stringptr, &stringptr, 0);
  }
  if (*corners <= dim) {
    printf("  Error:  Elements in %s have only %d corners.\n", fname,
           *corners);
    return 1;
  }

  /* Read and check number of element attributes. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    extras = 0;
  } else {
    extras = (showmelong) strtol(stringptr, &stringptr, 0);
  }
  if ((extras < 0) && !quiet) {
    printf("  Warning:  %s has negative value for number of attributes.\n",
           fname);
  }

  /* Allocate space to store the points. */
  *eleptr = (showmelong *)
    malloc((*elems + 1) * (dim + 1) * sizeof(showmelong));
  if (*eleptr == (showmelong *) NULL) {
    printf("  Error:  Out of memory.\n");
    return 1;
  }

  /* Read the elements.  The corner index `index' starts at 'dim + 1',     */
  /*   because elements are internally numbered from 1 (regardless of how  */
  /*   they're numbered in the file).  They are assumed to be triangles or */
  /*   tetrahedra, and the first 'dim + 1' nodes are the corners.          */
  index = dim + 1;
  smallerr = 1;
  for (i = firstnumber; i < firstnumber + *elems; i++) {
    stringptr = readline(inputline, infile, fname);
    elemnumber = (showmelong) strtol(stringptr, &stringptr, 0);

    /* If elements are not numbered as expected, print a warning. */
    if ((elemnumber != i) && smallerr) {
      printf("  Warning:  Elements in %s are not numbered correctly.\n",
             fname);
      printf("            (starting with element %ld).\n", (long) i);
      /* Don't print more minor errors after this. */
      smallerr = 0;
    }

    /* Read this element's corners (as point indices). */
    for (j = 0; j <= dim; j++) {
      stringptr = findfield(stringptr);
      if (*stringptr == '\0') {
        printf("Error:  Element %ld is missing a corner in %s.\n",
               (long) i, fname);
        /* Free the memory for points and return an error indication. */
        free(*eleptr);
        return 1;
      }
      /* Store the corner (adjusting it so the vertices are internally */
      /*   numbered from one) and advance the corner index.            */
      (*eleptr)[index] = (showmelong) strtol(stringptr, &stringptr, 0) + 1 -
                         firstnumber;

      /* Check if the corner (point index) is valid. */
      if (((*eleptr)[index] < 1) || ((*eleptr)[index] > nodes)) {
        printf("Error:  Triangle %ld has invalid corner in %s.\n",
               (long) i, fname);
        return 1;
      }

      index++;
    }
  }

  fclose(infile);

  if (dim == 3) {
    /* Make sure all the tetrahedra have the correct orientation. */
    for (i = 1; i <= *elems; i++) {
      if (orient3d(&nodeptr[(*eleptr)[4 * i] * 3],
                   &nodeptr[(*eleptr)[4 * i + 1] * 3],
                   &nodeptr[(*eleptr)[4 * i + 2] * 3],
                   &nodeptr[(*eleptr)[4 * i + 3] * 3]) < 0.0) {
        printf("Warning:  Element %ld is inverted in %s.\n",
               (long) (i + firstnumber - 1), fname);
        /* Fix its orientation. */
        swap = (*eleptr)[4 * i + 3];
        (*eleptr)[4 * i + 3] = (*eleptr)[4 * i + 2];
        (*eleptr)[4 * i + 2] = swap;
      }
    }

    /* Determine which tetrahedra adjoin which tetrahedra. */
    matchfaces(nodeptr, nodes, *elems, dim, *eleptr, &tetraptr);
  }

  return 0;
}

int loadedges(char *fname,
              int firstnumber,
              showmelong nodes,
              showmelong *edges,
              showmelong **edgeptr,
              showmereal **normptr)
{
  FILE *infile;
  char inputline[INPUTLINESIZE];
  char *stringptr;
  showmelong edgenumber;
  int edgemarks;
  showmelong i;
  showmelong index;
  int smallerr;

  if (!quiet) {
    printf("Opening %s.\n", fname);
  }
  infile = fopen(fname, "r");
  if (infile == (FILE *) NULL) {
    printf("  Error:  Cannot access file %s.\n", fname);
    return 1;
  }

  /* Read and check number of edges. */
  stringptr = readline(inputline, infile, fname);
  *edges = (showmelong) strtol(stringptr, &stringptr, 0);
  if (*edges < 1) {
    printf("  Error:  %s contains %ld edges.\n", fname, (long) *edges);
    return 1;
  }

  /* Read and check number of edge markers. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    edgemarks = 0;
  } else {
    edgemarks = (int) strtol(stringptr, &stringptr, 0);
  }
  if (edgemarks < 0) {
    printf("  Warning:  %s has negative value for number of edge markers.\n",
           fname);
  }
  if (edgemarks > 1) {
    printf("  Warning:  %s has value greater than one for number of edge "
           "markers.\n", fname);
  }

  /* Allocate space to store the edges. */
  *edgeptr = (showmelong *) malloc(((*edges + 1) << 1) * sizeof(showmelong));
  if (*edgeptr == (showmelong *) NULL) {
    printf("  Error:  Out of memory.\n");
    return 1;
  }

  /* Allocate space to store the directions of infinite rays. */
  *normptr = (showmereal *) malloc(((*edges + 1) << 1) * sizeof(showmereal));
  if (*normptr == (showmereal *) NULL) {
    printf("  Error:  Out of memory.\n");
    /* Free the memory for edges and return an error indication. */
    free(*edgeptr);
    return 1;
  }

  /* Read the edges.  The corner index `index' starts at 2, because    */
  /*   edges are internally numbered from 1 (regardless of how they're */
  /*   numbered in the file).                                          */
  index = 2;
  smallerr = 1;
  for (i = firstnumber; i < firstnumber + *edges; i++) {
    stringptr = readline(inputline, infile, fname);
    edgenumber = (showmelong) strtol(stringptr, &stringptr, 0);

    /* If edges are not numbered as expected, print a warning. */
    if ((edgenumber != i) && (smallerr)) {
      printf("  Warning:  Edges in %s are not numbered correctly.\n", fname);
      printf("            (starting with edge %ld).\n", (long) i);
      /* Don't print more minor errors after this. */
      smallerr = 0;
    }

    /* Read the first edge endpoint; adjust it so the vertices are */
    /*   internally numbered from one.                             */
    stringptr = findfield(stringptr);
    if (*stringptr == '\0') {
      printf("Error:  Edge %ld is missing its endpoints in %s.\n",
             (long) i, fname);
      /* Free the memory for everything and return an error indication. */
      free(*edgeptr);
      free(*normptr);
      return 1;
    }
    (*edgeptr)[index] = (showmelong) strtol(stringptr, &stringptr, 0) + 1 -
                        firstnumber;

    /* Check if the first endpoint is valid. */
    if (((*edgeptr)[index] < 1) || ((*edgeptr)[index] > nodes)) {
      printf("Error:  Edge %ld has invalid endpoint in %s.\n",
             (long) i, fname);
      free(*edgeptr);
      free(*normptr);
      return 1;
    }

    /* Read the second edge endpoint. */
    stringptr = findfield(stringptr);
    if (*stringptr == '\0') {
      printf("Error:  Edge %ld is missing an endpoint in %s.\n",
             (long) i, fname);
      /* Free the memory for everything and return an error indication. */
      free(*edgeptr);
      free(*normptr);
      return 1;
    }
    (*edgeptr)[index + 1] = (showmelong) strtol(stringptr, &stringptr, 0);

    /* Is this edge an infinite ray (in a Voronoi diagram)? */
    if ((*edgeptr)[index + 1] == -1) {
      /* Yes.  Read the x-coordinate of its direction. */
      stringptr = findfield(stringptr);
      if (*stringptr == '\0') {
        printf("Error:  Edge %ld is missing its direction in %s.\n",
               (long) i, fname);
        free(*edgeptr);
        free(*normptr);
        return 1;
      }
      (*normptr)[index] = (showmereal) strtod(stringptr, &stringptr);

      /* Read the y-coordinate of its direction. */
      stringptr = findfield(stringptr);
      if (*stringptr == '\0') {
        printf("Error:  Edge %ld is missing a direction coordinate in %s.\n",
               (long) i, fname);
        free(*edgeptr);
        free(*normptr);
        return 1;
      }
      (*normptr)[index + 1] = (showmereal) strtod(stringptr, &stringptr);
    } else {
      /* Adjust the second endpoint so the vertices are internally numbered */
      /*   from one.                                                        */
      (*edgeptr)[index + 1] += 1 - firstnumber;

      /* Check if the second endpoint is valid. */
      if (((*edgeptr)[index + 1] < 1) || ((*edgeptr)[index + 1] > nodes)) {
        printf("Error:  Edge %ld has invalid endpoint in %s.\n",
               (long) i, fname);
        free(*edgeptr);
        free(*normptr);
        return 1;
      }
    }

    index += 2;
  }

  fclose(infile);

  return 0;
}

int loadpart(char *fname,
             int dim,
             int firstnumber,
             showmelong elems,
             showmereal *nodeptr,
             showmelong *eleptr,
             int *subdomains,
             int **partition,
             showmereal **subdomcenter,
             showmereal **subdomshift)
{
  FILE *infile;
  char inputline[INPUTLINESIZE];
  char *stringptr;
  showmelong partelems;
  showmelong elemnumber;
  showmelong i, j;
  int k;
  showmelong index;
  int smallerr;
  showmelong *subsizes;

  if (!quiet) {
    printf("Opening %s.\n", fname);
  }
  infile = fopen(fname, "r");
  if (infile == (FILE *) NULL) {
    printf("  Error:  Cannot access file %s.\n", fname);
    return 1;
  }

  /* Read and check number of elements. */
  stringptr = readline(inputline, infile, fname);
  partelems = (showmelong) strtol(stringptr, &stringptr, 0);
  /* Does it match the number in the .ele file? */
  if (partelems != elems) {
    printf("  Error:  %s does not agree with .ele file on number of "
           "elements.\n", fname);
    return 1;
  }

  /* Read and check number of subdomains. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    *subdomains = 1;
  } else {
    *subdomains = (int) strtol(stringptr, &stringptr, 0);
  }
  if (*subdomains < 1) {
    printf("  Error:  %s specifies %d subdomains.\n", fname, *subdomains);
    return 1;
  }

  /* Allocate space to store the mapping from elements to subdomains. */
  *partition = (int *) malloc((elems + 1) * sizeof(int));
  if (*partition == (int *) NULL) {
    printf("  Error:  Out of memory.\n");
    return 1;
  }

  /* Read the mapping from elements to subdomains. */
  smallerr = 1;
  for (i = firstnumber; i < firstnumber + partelems; i++) {
    stringptr = readline(inputline, infile, fname);
    elemnumber = (showmelong) strtol(stringptr, &stringptr, 0);

    /* If elements are not numbered as expected, print a warning. */
    if ((elemnumber != i) && (smallerr)) {
      printf("  Warning:  Elements in %s are not numbered correctly.\n",
             fname);
      printf("            (starting with element %ld).\n", (long) i);
      /* Don't print more minor errors after this. */
      smallerr = 0;
    }

    /* Read the first subdomain; adjust it so the subdomains are */
    /*   internally numbered from zero.                          */
    stringptr = findfield(stringptr);
    if (*stringptr == '\0') {
      printf("Error:  Element %ld has no subdomain in %s.\n",
             (long) i, fname);
      free(*partition);
      return 1;
    }
    /* Index j is adjusted so elements are internally numbered from one. */
    j = i + 1 - firstnumber;
    (*partition)[j] = (int) strtol(stringptr, &stringptr, 0) - firstnumber;

    /* Check if the subdomain number is valid. */
    if (((*partition)[j] >= *subdomains) || ((*partition)[j] < 0)) {
      printf("  Error:  Element %ld of %s has an invalid subdomain.\n",
             (long) i, fname);
      /* Free the memory for subdomains and return an error indication. */
      free(*partition);
      return 1;
    }
  }

  fclose(infile);

  /* Allocate space to hold the center of mass of each subdomain. */
  *subdomcenter = (showmereal *)
                  malloc((*subdomains + 1) * dim * sizeof(showmereal));
  if (*subdomcenter == (showmereal *) NULL) {
    printf("Error:  Out of memory.\n");
    free(*partition);
    return 1;
  }

  /* Allocate space to hold the relative displacement of each subdomain. */
  *subdomshift = (showmereal *) malloc(*subdomains * dim * sizeof(showmereal));
  if (*subdomshift == (showmereal *) NULL) {
    printf("Error:  Out of memory.\n");
    free(*partition);
    free(*subdomcenter);
    return 1;
  }

  /* Allocate space to hold the number of element corners in each subdomain. */
  subsizes = (showmelong *) malloc((*subdomains + 1) * sizeof(showmelong));
  if (subsizes == (showmelong *) NULL) {
    printf("Error:  Out of memory.\n");
    free(*partition);
    free(*subdomcenter);
    free(*subdomshift);
    return 1;
  }

  /* Initialize subdomain size and center. */
  for (i = 0; i <= *subdomains; i++) {
    subsizes[i] = 0;
    for (j = 0; j < dim; j++) {
      (*subdomcenter)[i * dim + j] = 0.0;
    }
  }

  /* Iterate over the elements.  The corner index `index' starts at */
  /*   `dim + 1', because elements are internally numbered from 1.  */
  index = dim + 1;
  for (i = 1; i <= elems; i++) {
    /* Sum the `dim + 1' corners of this element into `subdomcenter' . */
    for (j = 0; j < dim + 1; j++) {
      for (k = 0; k < dim; k++) {
        (*subdomcenter)[(*partition)[i] * dim + k] +=
          nodeptr[eleptr[index] * dim + k];
      }
      index++;
    }
    /* Keep track of the total number of corners in the sum. */
    subsizes[(*partition)[i]] += dim + 1;
  }

  /* Compute the subdomain centers of mass. */
  for (i = 0; i < *subdomains; i++) {
    for (j = 0; j < dim; j++) {
      /* Divide total by number of subdomains. */
      (*subdomcenter)[i * dim + j] /= (showmereal) subsizes[i];
      /* Maintain a grand total of subdomain centers of mass. */
      (*subdomcenter)[*subdomains * dim + j] += (*subdomcenter)[i * dim + j];
    }
  }
  /* Compute a center of mass of the centers of mass. */
  for (j = 0; j < dim; j++) {
    (*subdomcenter)[*subdomains * dim + j] /= (showmereal) *subdomains;
  }

  /* `subsizes' is no longer needed. */
  free(subsizes);

  return 0;
}

int loadadj(char *fname,
            int *subdomains,
            int **ptr)
{
  FILE *infile;
  char inputline[INPUTLINESIZE];
  char *stringptr;
  int i, j;

  if (!quiet) {
    printf("Opening %s.\n", fname);
  }
  infile = fopen(fname, "r");
  if (infile == (FILE *) NULL) {
    printf("  Error:  Cannot access file %s.\n", fname);
    return 1;
  }

  /* Read and check number of subdomains. */
  stringptr = readline(inputline, infile, fname);
  if (*stringptr == '\0') {
    *subdomains = 1;
  } else {
    *subdomains = (int) strtol(stringptr, &stringptr, 0);
  }
  if (*subdomains < 1) {
    printf("  Error:  %s specifies %d subdomains.\n", fname, *subdomains);
    return 1;
  }

  /* Allocate space to store the adjacency graph. */
  *ptr = (int *) malloc(*subdomains * *subdomains * sizeof(int));
  if (*ptr == (int *) NULL) {
    printf("  Error:  Out of memory.\n");
    return 1;
  }

  /* Read the adjacency graph. */
  for (i = 0; i < *subdomains; i++) {
    for (j = 0; j < *subdomains; j++) {
      stringptr = readline(inputline, infile, fname);
      (*ptr)[i * *subdomains + j] = (int) strtol(stringptr, &stringptr, 0);
    }
  }
  return 0;
}

int loaddata(char *fname,
             int firstnumber,
             showmelong nodes,
             int *datadim,
             showmereal **dataptr,
             showmereal *datahist)
{
  FILE *infile;
  char inputline[INPUTLINESIZE];
  char *stringptr;
  showmelong datavalues;
  showmelong edgenumber;
  showmelong i;
  showmelong index;
  int smallerr;

  if (!quiet) {
    printf("Opening %s.\n", fname);
  }
  infile = fopen(fname, "r");
  if (infile == (FILE *) NULL) {
    printf("  Error:  Cannot access file %s.\n", fname);
    return 1;
  }

  /* Read and check number of nodes. */
  stringptr = readline(inputline, infile, fname);
  datavalues = (showmelong) strtol(stringptr, &stringptr, 0);
  if (datavalues != nodes) {
    printf("  Error:  %s does not agree with .node file on number of "
           "nodes.\n", fname);
    return 1;
  }

  /* Read and check number of data per node. */
  stringptr = findfield(stringptr);
  if (*stringptr == '\0') {
    *datadim = 1;
  } else {
    *datadim = (int) strtol(stringptr, &stringptr, 0);
  }
  if (*datadim < 1) {
    printf("  Error:  %s specifies %d data values per node.\n",
           fname, *datadim);
    return 1;
  }

  /* Allocate space to store the data. */
  *dataptr = (showmereal *) malloc((datavalues + 1) * sizeof(showmereal));
  if (*dataptr == (showmereal *) NULL) {
    printf("  Error:  Out of memory.\n");
    return 1;
  }

  /* Read the data. */
  index = 1;
  smallerr = 1;
  for (i = firstnumber; i < firstnumber + datavalues; i++) {
    stringptr = readline(inputline, infile, fname);
    edgenumber = (showmelong) strtol(stringptr, &stringptr, 0);

    /* If data are not numbered as expected, print a warning. */
    if ((edgenumber != i) && (smallerr)) {
      printf("  Warning:  Data in %s are not numbered correctly.\n", fname);
      printf("            (starting with data value %ld).\n", (long) i);
      /* Don't print more minor errors after this. */
      smallerr = 0;
    }

    stringptr = findfield(stringptr);
    if (*stringptr == '\0') {
      printf("  Error:  Datum %ld is missing from %s.\n", (long) i, fname);
      free(*dataptr);
      return 1;
    }
    (*dataptr)[index++] = (showmereal) strtod(stringptr, &stringptr);

    /* Keep track of the least and greatest data. */
    if (i == firstnumber) {
      datahist[0] = (*dataptr)[index - 1];
      datahist[1] = (*dataptr)[index - 1];
    } else {
      if (datahist[0] > (*dataptr)[index - 1]) {
        datahist[0] = (*dataptr)[index - 1];
      }
      if (datahist[1] < (*dataptr)[index - 1]) {
        datahist[1] = (*dataptr)[index - 1];
      }
    }
  }

  fclose(infile);

  return 0;
}

void findsubdomshift(int dim,
                     int subdomains,
                     showmereal explosion,
                     showmereal *subdomcenter,
                     showmereal *subdomshift)
{
  int i, j;

  /* Loop through subdomains and coordinates of each subdomain's center. */
  for (i = 0; i < subdomains; i++) {
    for (j = 0; j < dim; j++) {
      /* Each subdomain is shifted away from the center of mass of all the */
      /*   subdomains, by the factor `explosion'.                          */
      subdomshift[i * dim + j] = explosion *
        (subdomcenter[i * dim + j] - subdomcenter[subdomains * dim + j]);
    }
  }
}

int load_image(int inc,
               int image)
{
  int error;

  switch (image) {
    case NODE:
      error = loadnodes(nodefilename[inc], &firstnumber[inc], &nodes[inc],
                        &nodedim[inc], &nodeptr[inc],
                        &xlo[inc][NODE], &ylo[inc][NODE], &zlo[inc][NODE],
                        &xhi[inc][NODE], &yhi[inc][NODE], &zhi[inc][NODE]);
      break;
    case POLY:
      error = loadpoly(inc, polyfilename[inc], &firstnumber[inc],
                       &polynodes[inc], &polydim[inc], &polyedges[inc],
                       &polyholes[inc], &polynodeptr[inc], &polysegptr[inc],
                       &polyholeptr[inc],
                       &xlo[inc][POLY], &ylo[inc][POLY], &zlo[inc][POLY],
                       &xhi[inc][POLY], &yhi[inc][POLY], &zhi[inc][POLY]);
      break;
    case ELE:
      error = loadelems(elefilename[inc], nodedim[inc], firstnumber[inc],
                        nodes[inc], nodeptr[inc], &elems[inc],
                        &elecorners[inc], &eleptr[inc]);
      xlo[inc][ELE] = xlo[inc][NODE];
      ylo[inc][ELE] = ylo[inc][NODE];
      zlo[inc][ELE] = zlo[inc][NODE];
      xhi[inc][ELE] = xhi[inc][NODE];
      yhi[inc][ELE] = yhi[inc][NODE];
      zhi[inc][ELE] = zhi[inc][NODE];
      break;
    case EDGE:
      error = loadedges(edgefilename[inc], firstnumber[inc], nodes[inc],
                        &edges[inc], &edgeptr[inc], &normptr[inc]);
      xlo[inc][EDGE] = xlo[inc][NODE];
      ylo[inc][EDGE] = ylo[inc][NODE];
      zlo[inc][EDGE] = zlo[inc][NODE];
      xhi[inc][EDGE] = xhi[inc][NODE];
      yhi[inc][EDGE] = yhi[inc][NODE];
      zhi[inc][EDGE] = zhi[inc][NODE];
      break;
    case PART:
      error = loadpart(partfilename[inc], nodedim[inc], firstnumber[inc],
                       elems[inc], nodeptr[inc], eleptr[inc],
                       &subdomains[inc], &partition[inc], &subdomcenter[inc],
                       &subdomshift[inc]);
      if (!error) {
        findsubdomshift(nodedim[inc], subdomains[inc], explosion,
                        subdomcenter[inc], subdomshift[inc]);
      }
      xlo[inc][PART] = xlo[inc][NODE];
      ylo[inc][PART] = ylo[inc][NODE];
      zlo[inc][PART] = zlo[inc][NODE];
      xhi[inc][PART] = xhi[inc][NODE];
      yhi[inc][PART] = yhi[inc][NODE];
      zhi[inc][PART] = zhi[inc][NODE];
      break;
    case ADJ:
      error = loadadj(adjfilename[inc], &adjsubdomains[inc], &adjptr[inc]);
      xlo[inc][ADJ] = xlo[inc][NODE];
      ylo[inc][ADJ] = ylo[inc][NODE];
      zlo[inc][ADJ] = zlo[inc][NODE];
      xhi[inc][ADJ] = xhi[inc][NODE];
      yhi[inc][ADJ] = yhi[inc][NODE];
      zhi[inc][ADJ] = zhi[inc][NODE];
      break;
    case VORO:
      error = loadnodes(vnodefilename[inc], &firstnumber[inc], &vnodes[inc],
                        &vnodedim[inc], &vnodeptr[inc],
                        &xlo[inc][VORO], &ylo[inc][VORO], &zlo[inc][VORO],
                        &xhi[inc][VORO], &yhi[inc][VORO], &zhi[inc][VORO]);
      if (!error) {
        error = loadedges(vedgefilename[inc], firstnumber[inc], vnodes[inc],
                          &vedges[inc], &vedgeptr[inc], &vnormptr[inc]);
      }
      break;
    case DATA:
      error = loaddata(datafilename[inc], firstnumber[inc], nodes[inc],
                       &datadim[inc], &dataptr[inc], datahist[inc]);
      xlo[inc][DATA] = xlo[inc][NODE];
      ylo[inc][DATA] = ylo[inc][NODE];
      zlo[inc][DATA] = zlo[inc][NODE];
      xhi[inc][DATA] = xhi[inc][NODE];
      yhi[inc][DATA] = yhi[inc][NODE];
      zhi[inc][DATA] = zhi[inc][NODE];
      break;
    default:
      error = 1;
  }
  if (!error) {
    loaded[inc][image] = 1;
  }
  return error;
}

void choose_image(int inc,
                  int image)
{
  if (!loaded[inc][image]) {
    if ((image == ELE) || (image == EDGE) || (image == PART) || (image == ADJ)
        || (image == DATA)) {
      if (!loaded[inc][NODE]) {
        if (load_image(inc, NODE)) {
          return;
        }
      }
    }
    if ((image == PART) || (image == ADJ) || (image == DATA)) {
      if (!loaded[inc][ELE]) {
        if (load_image(inc, ELE)) {
          return;
        }
      }
    }
    if (image == ADJ) {
      if (!loaded[inc][PART]) {
        if (load_image(inc, PART)) {
          return;
        }
      }
    }
    if (load_image(inc, image)) {
      return;
    }
  }
  current_inc = inc;
  current_image = image;
}

Window make_button(char *name,
                   int x,
                   int y,
                   unsigned int width)
{
  XSetWindowAttributes attr;
  XSizeHints hints;
  Window button;

  attr.background_pixel = black;
  attr.border_pixel = white;
  attr.backing_store = NotUseful;
  attr.event_mask = ExposureMask | ButtonReleaseMask | ButtonPressMask;
  attr.bit_gravity = SouthWestGravity;
  attr.win_gravity = SouthWestGravity;
  attr.save_under = False;
  button = XCreateWindow(display, mainwindow, x, y, width, BUTTONHEIGHT - 4,
                         2, 0, InputOutput, CopyFromParent,
                         CWBackPixel | CWBorderPixel | CWEventMask |
                         CWBitGravity | CWWinGravity | CWBackingStore |
                         CWSaveUnder, &attr);
  hints.width = width;
  hints.height = BUTTONHEIGHT - 4;
  hints.min_width = 0;
  hints.min_height = BUTTONHEIGHT - 4;
  hints.max_width = width;
  hints.max_height = BUTTONHEIGHT - 4;
  hints.width_inc = 1;
  hints.height_inc = 1;
  hints.flags = PMinSize | PMaxSize | PSize | PResizeInc;
  XSetStandardProperties(display, button, name, "showme", None, (char **) NULL,
                         0, &hints);
  return button;
}

void make_buttons(int y)
{
  char rotatewinname[2];
  int i;

  for (i = 1; i >= 0; i--) {
    nodewin[i] = make_button("node", 0, y + (1 - i) * BUTTONHEIGHT, 42);
    XMapWindow(display, nodewin[i]);
    polywin[i] = make_button("poly", 44, y + (1 - i) * BUTTONHEIGHT, 42);
    XMapWindow(display, polywin[i]);
    elewin[i] = make_button("ele", 88, y + (1 - i) * BUTTONHEIGHT, 33);
    XMapWindow(display, elewin[i]);
    edgewin[i] = make_button("edge", 123, y + (1 - i) * BUTTONHEIGHT, 42);
    XMapWindow(display, edgewin[i]);
    partwin[i] = make_button("part", 167, y + (1 - i) * BUTTONHEIGHT, 42);
    XMapWindow(display, partwin[i]);
    adjwin[i] = make_button("adj", 211, y + (1 - i) * BUTTONHEIGHT, 33);
    XMapWindow(display, adjwin[i]);
    voronoiwin[i] = make_button("voro", 246, y + (1 - i) * BUTTONHEIGHT, 42);
    XMapWindow(display, voronoiwin[i]);
    datawin[i] = make_button("data", 290, y + (1 - i) * BUTTONHEIGHT, 42);
    XMapWindow(display, datawin[i]);

  }
  versionpluswin = make_button("    +", 334, y, 52);
  XMapWindow(display, versionpluswin);
  versionminuswin = make_button("    -", 334, y + BUTTONHEIGHT, 52);
  XMapWindow(display, versionminuswin);

  motionwin = make_button("Rot", 0, y + 2 * BUTTONHEIGHT, 33);
  XMapWindow(display, motionwin);
  for (i = 0; i < 6; i++) {
    sprintf(rotatewinname, "%d", i);
    rotatewin[i] = make_button(rotatewinname, 35 + i * 20,
                               y + 2 * BUTTONHEIGHT, 18);
    XMapWindow(display, rotatewin[i]);
  }
  rotateamtwin = make_button("Amt", 155, y + 2 * BUTTONHEIGHT, 33);
  XMapWindow(display, rotateamtwin);
  wireframeoptionwin = make_button("Wire", 190, y + 2 * BUTTONHEIGHT, 42);
  XMapWindow(display, wireframeoptionwin);
  cutleftwin = make_button("Cut<", 234, y + 2 * BUTTONHEIGHT, 42);
  XMapWindow(display, cutleftwin);
  cutrightwin = make_button(">", 278, y + 2 * BUTTONHEIGHT, 14);
  XMapWindow(display, cutrightwin);
  cutupwin = make_button("^", 294, y + 2 * BUTTONHEIGHT, 14);
  XMapWindow(display, cutupwin);
  cutdownwin = make_button("v", 310, y + 2 * BUTTONHEIGHT, 14);
  XMapWindow(display, cutdownwin);
  perspectivewin = make_button("Persp", 326, y + 2 * BUTTONHEIGHT, 52);
  XMapWindow(display, perspectivewin);
  perspluswin = make_button("+", 380, y + 2 * BUTTONHEIGHT, 14);
  XMapWindow(display, perspluswin);
  persminuswin = make_button("-", 396, y + 2 * BUTTONHEIGHT, 14);
  XMapWindow(display, persminuswin);
  qualitywin = make_button("Q", 396, y + BUTTONHEIGHT, 14);
  XMapWindow(display, qualitywin);

  quitwin = make_button("Quit", 0, y + 3 * BUTTONHEIGHT, 42);
  XMapWindow(display, quitwin);
  leftwin = make_button("<", 44, y + 3 * BUTTONHEIGHT, 14);
  XMapWindow(display, leftwin);
  rightwin = make_button(">", 60, y + 3 * BUTTONHEIGHT, 14);
  XMapWindow(display, rightwin);
  upwin = make_button("^", 76, y + 3 * BUTTONHEIGHT, 14);
  XMapWindow(display, upwin);
  downwin = make_button("v", 92, y + 3 * BUTTONHEIGHT, 14);
  XMapWindow(display, downwin);
  resetwin = make_button("Reset", 108, y + 3 * BUTTONHEIGHT, 52);
  XMapWindow(display, resetwin);
  widthpluswin = make_button("Width+", 162, y + 3 * BUTTONHEIGHT, 61);
  XMapWindow(display, widthpluswin);
  widthminuswin = make_button("-", 225, y + 3 * BUTTONHEIGHT, 14);
  XMapWindow(display, widthminuswin);
  expwin = make_button("Exp", 241, y + 3 * BUTTONHEIGHT, 33);
  XMapWindow(display, expwin);
  exppluswin = make_button("+", 276, y + 3 * BUTTONHEIGHT, 14);
  XMapWindow(display, exppluswin);
  expminuswin = make_button("-", 292, y + 3 * BUTTONHEIGHT, 14);
  XMapWindow(display, expminuswin);
  fillwin = make_button("Fill", 308, y + 3 * BUTTONHEIGHT, 41);
  XMapWindow(display, fillwin);
  pswin = make_button("PS", 351, y + 3 * BUTTONHEIGHT, 24);
  XMapWindow(display, pswin);
  epswin = make_button("EPS", 377, y + 3 * BUTTONHEIGHT, 33);
  XMapWindow(display, epswin);
}

void fill_button(Window button)
{
  int x, y;
  unsigned int w, h, d, b;
  Window rootw;

  XGetGeometry(display, button, &rootw, &x, &y, &w, &h, &d, &b);
  XFillRectangle(display, button, fontgc, 0, 0, w, h);
}

void draw_buttons()
{
  char numberstring[32];
  char buttonstring[6];
  int rotatenumber;
  int i;

  for (i = 1; i >= 0; i--) {
    if ((current_image == NODE) && (current_inc == i)) {
      fill_button(nodewin[i]);
      XDrawString(display, nodewin[i], blackfontgc, 2, 13, "node", 4);
    } else {
      XClearWindow(display, nodewin[i]);
      XDrawString(display, nodewin[i], fontgc, 2, 13, "node", 4);
    }
    if ((current_image == POLY) && (current_inc == i)) {
      fill_button(polywin[i]);
      XDrawString(display, polywin[i], blackfontgc, 2, 13, "poly", 4);
    } else {
      XClearWindow(display, polywin[i]);
      XDrawString(display, polywin[i], fontgc, 2, 13, "poly", 4);
    }
    if ((current_image == ELE) && (current_inc == i)) {
      fill_button(elewin[i]);
      XDrawString(display, elewin[i], blackfontgc, 2, 13, "ele", 3);
    } else {
      XClearWindow(display, elewin[i]);
      XDrawString(display, elewin[i], fontgc, 2, 13, "ele", 3);
    }
    if ((current_image == EDGE) && (current_inc == i)) {
      fill_button(edgewin[i]);
      XDrawString(display, edgewin[i], blackfontgc, 2, 13, "edge", 4);
    } else {
      XClearWindow(display, edgewin[i]);
      XDrawString(display, edgewin[i], fontgc, 2, 13, "edge", 4);
    }
    if ((current_image == PART) && (current_inc == i)) {
      fill_button(partwin[i]);
      XDrawString(display, partwin[i], blackfontgc, 2, 13, "part", 4);
    } else {
      XClearWindow(display, partwin[i]);
      XDrawString(display, partwin[i], fontgc, 2, 13, "part", 4);
    }
    if ((current_image == ADJ) && (current_inc == i)) {
      fill_button(adjwin[i]);
      XDrawString(display, adjwin[i], blackfontgc, 2, 13, "adj", 3);
    } else {
      XClearWindow(display, adjwin[i]);
      XDrawString(display, adjwin[i], fontgc, 2, 13, "adj", 3);
    }
    if ((current_image == VORO) && (current_inc == i)) {
      fill_button(voronoiwin[i]);
      XDrawString(display, voronoiwin[i], blackfontgc, 2, 13, "voro", 4);
    } else {
      XClearWindow(display, voronoiwin[i]);
      XDrawString(display, voronoiwin[i], fontgc, 2, 13, "voro", 4);
    }
    if ((current_image == DATA) && (current_inc == i)) {
      fill_button(datawin[i]);
      XDrawString(display, datawin[i], blackfontgc, 2, 13, "data", 4);
    } else {
      XClearWindow(display, datawin[i]);
      XDrawString(display, datawin[i], fontgc, 2, 13, "data", 4);
    }
  }

  XClearWindow(display, versionpluswin);
  sprintf(numberstring, "%d", loweriteration + 1);
  sprintf(buttonstring, "%-4.4s+", numberstring);
  XDrawString(display, versionpluswin, fontgc, 2, 13, buttonstring, 5);
  XClearWindow(display, versionminuswin);
  sprintf(numberstring, "%d", loweriteration);
  if (loweriteration == 0) {
    sprintf(buttonstring, "%-4.4s", numberstring);
  } else {
    sprintf(buttonstring, "%-4.4s-", numberstring);
  }
  XDrawString(display, versionminuswin, fontgc, 2, 13, buttonstring, 5);

  XClearWindow(display, motionwin);
  for (rotatenumber = 0; rotatenumber < 6; rotatenumber++) {
    XClearWindow(display, rotatewin[rotatenumber]);
  }
  XClearWindow(display, rotateamtwin);
  XClearWindow(display, wireframeoptionwin);
  XClearWindow(display, perspluswin);
  XClearWindow(display, persminuswin);
  XClearWindow(display, perspectivewin);
  XClearWindow(display, cutleftwin);
  XClearWindow(display, cutrightwin);
  XClearWindow(display, cutupwin);
  XClearWindow(display, cutdownwin);
  XClearWindow(display, qualitywin);
  if ((current_image == DATA) || (nodedim[current_inc] == 3)) {
    if (motion) {
      fill_button(motionwin);
      XDrawString(display, motionwin, blackfontgc, 2, 13, "Rot", 3);
    } else {
      XDrawString(display, motionwin, fontgc, 2, 13, "Rot", 3);
    }
    /* Draw the little pan, tilt, and twist arrow indicators */
    XDrawArc(display, rotatewin[0], fontgc, 4, 2, 8, 12, -5760, -16000);
    XDrawRectangle(display, rotatewin[0], fontgc, 9, 12, 2, 2);
    XDrawArc(display, rotatewin[1], fontgc, 4, 2, 8, 12, -5760, -16000);
    XDrawRectangle(display, rotatewin[1], fontgc, 11, 4, 2, 2);
    XDrawArc(display, rotatewin[2], fontgc, 2, 4, 12, 8, 0, -16000);
    XDrawRectangle(display, rotatewin[2], fontgc, 6, 3, 2, 2);
    XDrawArc(display, rotatewin[3], fontgc, 2, 4, 12, 8, 0, -16000);
    XDrawRectangle(display, rotatewin[3], fontgc, 13, 6, 2, 2);
    XDrawArc(display, rotatewin[4], fontgc, 2, 2, 12, 12, -1280, -21760);
    XDrawRectangle(display, rotatewin[4], fontgc, 13, 11, 2, 2);
    XDrawArc(display, rotatewin[5], fontgc, 2, 2, 12, 12, -1280, -21760);
    XDrawRectangle(display, rotatewin[5], fontgc, 13, 5, 2, 2);
    XDrawString(display, rotateamtwin, fontgc, 2, 13, "Amt", 3);
    if (wireframe) {
      fill_button(wireframeoptionwin);
      XDrawString(display, wireframeoptionwin, blackfontgc, 2, 13, "Wire", 4);
    } else {
      XDrawString(display, wireframeoptionwin, fontgc, 2, 13, "Wire", 4);
    }
    if (perspective) {
      fill_button(perspectivewin);
      XDrawString(display, perspectivewin, blackfontgc, 2, 13, "Persp", 5);
      XDrawString(display, perspluswin, fontgc, 2, 13, "+", 1);
      XDrawString(display, persminuswin, fontgc, 2, 13, "-", 1);
    } else {
      XDrawString(display, perspectivewin, fontgc, 2, 13, "Persp", 5);
    }
    if (nodedim[current_inc] == 3) {
      XDrawString(display, cutleftwin, fontgc, 2, 13, "Cut<", 4);
      XDrawString(display, cutrightwin, fontgc, 2, 13, ">", 1);
      XDrawString(display, cutupwin, fontgc, 2, 13, "^", 1);
      XDrawString(display, cutdownwin, fontgc, 2, 13, "v", 1);
      if ((current_image == ELE) || (current_image == PART)
          || (current_image == DATA)) {
        XDrawString(display, qualitywin, fontgc, 2, 13, "Q", 1);
      }
    }
  }

  XClearWindow(display, quitwin);
  XDrawString(display, quitwin, fontgc, 2, 13, "Quit", 4);
  XClearWindow(display, leftwin);
  XDrawString(display, leftwin, fontgc, 2, 13, "<", 1);
  XClearWindow(display, rightwin);
  XDrawString(display, rightwin, fontgc, 2, 13, ">", 1);
  XClearWindow(display, upwin);
  XDrawString(display, upwin, fontgc, 2, 13, "^", 1);
  XClearWindow(display, downwin);
  XDrawString(display, downwin, fontgc, 2, 13, "v", 1);
  XClearWindow(display, resetwin);
  XDrawString(display, resetwin, fontgc, 2, 13, "Reset", 6);
  XClearWindow(display, widthpluswin);
  if (line_width < 100) {
    XDrawString(display, widthpluswin, fontgc, 2, 13, "Width+", 6);
  } else {
    XDrawString(display, widthpluswin, fontgc, 2, 13, "Width ", 6);
  }
  XClearWindow(display, widthminuswin);
  if (line_width > 1) {
    XDrawString(display, widthminuswin, fontgc, 2, 13, "-", 1);
  }
  XClearWindow(display, expwin);
  XClearWindow(display, exppluswin);
  XClearWindow(display, expminuswin);
  XClearWindow(display, fillwin);
  if (current_image == PART) {
    if (explode) {
      fill_button(expwin);
      XDrawString(display, expwin, blackfontgc, 2, 13, "Exp", 3);
    } else {
      XDrawString(display, expwin, fontgc, 2, 13, "Exp", 3);
    }
    XDrawString(display, exppluswin, fontgc, 2, 13, "+", 1);
    XDrawString(display, expminuswin, fontgc, 2, 13, "-", 1);
  }
  if ((current_image == PART) || (current_image == DATA)) {
    if (fillelem) {
      fill_button(fillwin);
      XDrawString(display, fillwin, blackfontgc, 2, 13, "Fill", 4);
    } else {
      XDrawString(display, fillwin, fontgc, 2, 13, "Fill", 4);
    }
  }
  XClearWindow(display, pswin);
  XDrawString(display, pswin, fontgc, 2, 13, "PS", 2);
  XClearWindow(display, epswin);
  XDrawString(display, epswin, fontgc, 2, 13, "EPS", 3);
}

Window create_popup_window(char *name,
                           int x,
                           int y,
                           unsigned int width,
                           unsigned int height,
                           int bw,
                           int back_bw)
{
  XSetWindowAttributes attr;
  XSizeHints hints;
  Window tmpwin;

  black = BlackPixel(display, screen);
  white = WhitePixel(display, screen);
  windowdepth = DefaultDepth(display, screen);
  rootmap = DefaultColormap(display, screen);
  attr.background_pixel = white;
  attr.border_pixel = black;
  attr.backing_store = NotUseful;
  attr.event_mask = ExposureMask | ButtonReleaseMask | ButtonPressMask
                  | StructureNotifyMask;
  attr.bit_gravity = NorthWestGravity;
  attr.win_gravity = NorthWestGravity;
  attr.save_under = False;
  tmpwin=XCreateWindow(display, rootwindow, x, y, width,
                       height, 3, 0,
                       InputOutput, CopyFromParent,
                       CWBackPixel | CWBorderPixel | CWEventMask
                       | CWBitGravity | CWWinGravity | CWBackingStore
                       | CWSaveUnder, &attr);
  hints.min_width = 0;
  hints.min_height = 0;
  hints.max_width = width;
  hints.max_height = height;
  hints.width_inc = 1;
  hints.height_inc = 1;
  hints.flags = PMinSize | PSize | PResizeInc;

  XSetStandardProperties(display, tmpwin, name, "popup", None, 0, 0, &hints);
  XClearWindow(display, tmpwin);
  XMapWindow(display, tmpwin);
  XFlush(display);

  return tmpwin;
}

char answer[132]; /* A temporary global so no mallocing is done by get_line */

char *get_line(char *prompt)
{
  Window popup, root_ret;

  int x, y;
  unsigned int w_ret, h_ret, bw_ret, d_ret;
  char string[10];
  int nchar, num_letters;
  char c;

  XGetGeometry(display, rotateamtwin, &root_ret, &x, &y, &w_ret, &h_ret,
               &bw_ret, &d_ret);

  popup = create_popup_window("Dialog", x, y,
                              strlen(prompt) * 10 + 82, 30, 4, 1);
  XSelectInput(display, popup, KeyPressMask);

  XMapWindow(display, popup);
  XClearWindow(display, popup);

  XDrawString(display, popup, blackfontgc, 2, 17, prompt,
              (int) strlen(prompt));
  XFlush(display);

  num_letters = 0;

/*
  XFillRectangle(display, popup, fontgc,
                 (strlen(prompt) + num_letters) * 10 + 12, 9, 6, 10);
*/

  while (1) {
    XMaskEvent(display, KeyPressMask, &event);

    nchar = XLookupString(&event.xkey, string, 10, NULL, NULL);
    if (nchar == 0) {
      continue;
    }

    c = *string;

    if (c == '\r') {
      break;
    }

    if ((c == '\b') || (c == '\177')) { /* backspace */
      if (num_letters > 0) {
	XFillRectangle(display, popup, fontgc,
                       ((int) strlen(prompt) + num_letters) * 10 + 12,
                       9, 6, 10);
	num_letters -= 1;
	XFillRectangle(display, popup, blackfontgc,
                       ((int) strlen(prompt) + num_letters) * 10 + 12,
                       9, 6, 10);
	answer[num_letters] = '\0';
      }
    }
    else if (num_letters < 130) {
      XFillRectangle(display, popup, fontgc,
                     ((int) strlen(prompt) + num_letters) * 10 + 12, 9, 6, 10);
      ++num_letters;
      XFillRectangle(display, popup, blackfontgc,
                     ((int) strlen(prompt) + num_letters) * 10 + 12, 9, 6, 10);
      answer[num_letters - 1] = c;
      answer[num_letters] = '\0';

      XDrawString(display, popup, blackfontgc,
                  ((int) strlen(prompt) + num_letters) * 10 + 2,
                  17, string, 1);
    }
    XFlush(display);
  }
  XDestroyWindow(display,popup);
  XFlush(display);
  return answer;
}

void showme_window(int argc,
                   char **argv)
{
  XSetWindowAttributes attr;
  XSizeHints hints;
  XGCValues fontvalues, linevalues;
  XColor alloc_color, exact_color;
  char grayname[8];
  int i;

  display = XOpenDisplay((char *) NULL);
  if (!display) {
    printf("Error:  Cannot open display.\n");
    exit(1);
  }
  screen = DefaultScreen(display);
  rootwindow = DefaultRootWindow(display);
  black = BlackPixel(display, screen);
  white = WhitePixel(display, screen);
  windowdepth = DefaultDepth(display, screen);
  rootmap = DefaultColormap(display, screen);
  width = STARTWIDTH;
  height = STARTHEIGHT;
  attr.background_pixel = black;
  attr.border_pixel = white;
  attr.backing_store = NotUseful;
  attr.event_mask = ExposureMask | ButtonReleaseMask | ButtonPressMask |
                    StructureNotifyMask | PointerMotionMask;
  attr.bit_gravity = NorthWestGravity;
  attr.win_gravity = NorthWestGravity;
  attr.save_under = False;
  mainwindow = XCreateWindow(display, rootwindow, 0, 0, width,
                             height + PANELHEIGHT, 3, 0,
                             InputOutput, CopyFromParent,
                             CWBackPixel | CWBorderPixel | CWEventMask |
                             CWBitGravity | CWWinGravity | CWBackingStore |
                             CWSaveUnder, &attr);
  hints.width = width;
  hints.height = height + PANELHEIGHT;
  hints.min_width = MINWIDTH;
  hints.min_height = MINHEIGHT + PANELHEIGHT;
  hints.width_inc = 1;
  hints.height_inc = 1;
  hints.flags = PMinSize | PSize | PResizeInc;
  XSetStandardProperties(display, mainwindow, "Show Me", "showme", None,
                         argv, argc, &hints);
  XChangeProperty(display, mainwindow, XA_WM_CLASS, XA_STRING, 8,
                  PropModeReplace, (unsigned char *) "showme\0Archimedes", 18);
  XClearWindow(display, mainwindow);
  XMapWindow(display, mainwindow);
  if ((windowdepth > 1) &&
      XAllocNamedColor(display, rootmap, "yellow", &alloc_color,
                       &exact_color)) {
    colordisplay = 1;
    explode = bw_ps;
    fontvalues.foreground = alloc_color.pixel;
    linevalues.foreground = alloc_color.pixel;
    showme_foreground = alloc_color.pixel;
    for (i = 0; i < MAXCOLORS; i++) {
      if (XAllocNamedColor(display, rootmap, colorname[i], &alloc_color,
                           &rgb[i])) {
        colors[i] = alloc_color.pixel;
      } else {
        colors[i] = white;
        rgb[i].red = alloc_color.red;
        rgb[i].green = alloc_color.green;
        rgb[i].blue = alloc_color.blue;
        if (!quiet) {
          printf("Warning:  I could not allocate %s.\n", colorname[i]);
        }
      }
    }
    for (i = 0; i < MAXGRAYS; i++) {
      sprintf(grayname, "gray%d",
              25 + (int) (75.0 * (showmereal) i / (showmereal) MAXGRAYS));
      if (XAllocNamedColor(display, rootmap, grayname, &alloc_color,
                           &gray[i])) {
        grays[i] = alloc_color.pixel;
      } else {
        grays[i] = white;
        gray[i].red = alloc_color.red;
        gray[i].green = alloc_color.green;
        gray[i].blue = alloc_color.blue;
        if (!quiet) {
          printf("Warning:  I could not allocate %s.\n", grayname);
        }
      }
    }
  } else {
    colordisplay = 0;
    fillelem = 0;
    explode = 1;
    fontvalues.foreground = white;
    linevalues.foreground = white;
    showme_foreground = white;
  }
  myfont = XLoadQueryFont(display, "9x15");
  fontvalues.background = black;
  fontvalues.font = myfont->fid;
  fontvalues.fill_style = FillSolid;
  fontvalues.line_width = 2;
  fontgc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
                      GCFont | GCLineWidth | GCFillStyle, &fontvalues);
  fontvalues.foreground = black;
  blackfontgc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
                         GCFont | GCLineWidth | GCFillStyle, &fontvalues);
  linevalues.background = black;
  linevalues.line_width = line_width;
  linevalues.cap_style = CapRound;
  linevalues.join_style = JoinRound;
  linevalues.fill_style = FillSolid;
  linegc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
                     GCLineWidth | GCCapStyle | GCJoinStyle | GCFillStyle,
                     &linevalues);
  linevalues.foreground = black;
  trianglegc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
                         GCLineWidth | GCCapStyle | GCJoinStyle | GCFillStyle,
                         &linevalues);
  make_buttons((int) height);
  XFlush(display);
}

void draw_node2d(showmelong nodes,
                 showmereal *nodeptr,
                 showmereal xcenter,
                 showmereal ycenter,
                 showmereal xscale,
                 showmereal yscale,
                 showmereal xoffset,
                 showmereal yoffset)
{
  showmelong i;
  showmelong index;

  index = 2;
  for (i = 1; i <= nodes; i++) {
    XFillRectangle(display, mainwindow, linegc,
                   (int) ((nodeptr[index] - xcenter) * xscale + xoffset -
                          (line_width >> 1)),
                   (int) ((nodeptr[index + 1] - ycenter) * yscale + yoffset -
                          (line_width >> 1)), line_width, line_width);
    index += 2;
  }
}

void draw_node3d(showmelong nodes,
                 showmereal *nodeptr,
                 showmereal xcenter,
                 showmereal ycenter,
                 showmereal zcenter,
                 showmereal xscale,
                 showmereal yscale,
                 showmereal xoffset,
                 showmereal yoffset)
{
  showmelong i;
  showmelong index;
  vector_t hpt;

  index = 3;
  for (i = 1; i <= nodes; i++) {
    hpt[0] = nodeptr[index++] - xcenter;
    hpt[1] = nodeptr[index++] - ycenter;
    hpt[2] = nodeptr[index++] - zcenter;
    mult_matvec(viewmatrix, hpt, hpt);
/*    perspectiveproj(hpt, &pt1); */
    XFillRectangle(display, mainwindow, linegc,
                   (int) (hpt[0] * xscale + xoffset - (line_width >> 1)),
                   (int) (hpt[1] * yscale + yoffset - (line_width >> 1)),
                   line_width, line_width);
  }
}

void draw_poly2d(showmelong nodes,
                 showmelong edges,
                 showmelong holes,
                 showmereal *nodeptr,
                 showmelong *edgeptr,
                 showmereal *holeptr,
                 showmereal xcenter,
                 showmereal ycenter,
                 showmereal xscale,
                 showmereal yscale,
                 showmereal xoffset,
                 showmereal yoffset)
{
  showmereal *point1, *point2;
  int x1, y1, x2, y2;
  showmelong i;
  showmelong index;

  index = 2;
  for (i = 1; i <= nodes; i++) {
    XFillRectangle(display, mainwindow, linegc,
                   (int) ((nodeptr[index] - xcenter) * xscale + xoffset -
                          (line_width >> 1)),
                   (int) ((nodeptr[index + 1] - ycenter) * yscale + yoffset -
                          (line_width >> 1)), line_width, line_width);
    index += 2;
  }
  index = 2;
  for (i = 1; i <= edges; i++) {
    point1 = &nodeptr[edgeptr[index++] * 2];
    point2 = &nodeptr[edgeptr[index++] * 2];
    XDrawLine(display, mainwindow, linegc,
              (int) ((point1[0] - xcenter) * xscale + xoffset),
              (int) ((point1[1] - ycenter) * yscale + yoffset),
              (int) ((point2[0] - xcenter) * xscale + xoffset),
              (int) ((point2[1] - ycenter) * yscale + yoffset));
  }
  index = 2;
  if (colordisplay) {
    XSetForeground(display, linegc, colors[0]);
  }
  for (i = 1; i <= holes; i++) {
    x1 = (int) ((holeptr[index] - xcenter) * xscale + xoffset) - 3;
    y1 = (int) ((holeptr[index + 1] - ycenter) * yscale + yoffset) - 3;
    x2 = x1 + 6;
    y2 = y1 + 6;
    XDrawLine(display, mainwindow, linegc, x1, y1, x2, y2);
    XDrawLine(display, mainwindow, linegc, x1, y2, x2, y1);
    index += 2;
  }
  XSetForeground(display, linegc, showme_foreground);
}

unsigned long randomnation(unsigned int choices)
{
  randomseed = (randomseed * 1366l + 150889l) % 714025l;
  return randomseed / (714025l / choices + 1);
}

/*
 *  Put the depth together with an index so the pair can be sorted
 *  according to depth
 */
struct facelist {
  showmereal z;
  int whichtet;
  int whichface;
  int color;
};

void sortfaces(struct facelist *drawfaces,
               int faces)
{
  struct facelist temp;
  showmereal pivotz;
  int pivot;
  int left, right;

  pivot = (int) randomnation((unsigned int) faces);
  pivotz = drawfaces[pivot].z;
  left = -1;
  right = faces;
  while (left < right) {
    do {
      left++;
    } while (drawfaces[left].z < pivotz);
    do {
      right--;
    } while (drawfaces[right].z > pivotz);
    if (left < right) {
      temp = drawfaces[left];
      drawfaces[left] = drawfaces[right];
      drawfaces[right] = temp;
    }
  }
  if (left > 1) {
    sortfaces(drawfaces, left);
  }
  if (right < faces - 2) {
    sortfaces(&drawfaces[right + 1], faces - right - 1);
  }
}

void draw_ele2d(showmelong elems,
                showmereal *nodeptr,
                showmelong *eleptr,
                int *partition,
                showmereal *shift,
                showmereal xcenter,
                showmereal ycenter,
                showmereal xscale,
                showmereal yscale,
                showmereal xoffset,
                showmereal yoffset)
{
  showmelong i;
  int j, k;
  int index;
  showmereal xshift, yshift;
  showmereal *nowpoint;
  XPoint vertices[3];

  index = 3;
  for (i = 1; i <= elems; i++) {
    if ((partition != (int *) NULL) && explode) {
      xshift = shift[partition[i] << 1];
      yshift = shift[(partition[i] << 1) + 1];
      for (j = 0; j < 3; j++) {
        nowpoint = &nodeptr[eleptr[index++] * 2];
        vertices[j].x = (short) ((nowpoint[0] - xcenter + xshift) * xscale
                                 + xoffset);
        vertices[j].y = (short) ((nowpoint[1] - ycenter + yshift) * yscale
                                 + yoffset);
      }
    } else {
      for (j = 0; j < 3; j++) {
        nowpoint = &nodeptr[eleptr[index++] * 2];
        vertices[j].x = (short) ((nowpoint[0] - xcenter) * xscale
                                 + xoffset);
        vertices[j].y = (short) ((nowpoint[1] - ycenter) * yscale
                                 + yoffset);
      }
    }
    if (colordisplay && (partition != (int *) NULL)) {
      if (fillelem) {
        XSetForeground(display, trianglegc,
                       colors[bitreverse[partition[i] & 63]]);
        XFillPolygon(display, mainwindow, trianglegc, vertices, 3,
                     Convex, CoordModeOrigin);
      } else {
        XSetForeground(display, linegc, colors[bitreverse[partition[i] & 63]]);
      }
    }
    k = 2;
    for (j = 0; j < 3; j++) {
      XDrawLine(display, mainwindow, linegc,
                vertices[j].x, vertices[j].y, vertices[k].x, vertices[k].y);
      k = j;
    }
  }
  XSetForeground(display, linegc, showme_foreground);
}

void draw_ele3d(showmelong elems,
                showmereal *nodeptr,
                showmelong *eleptr,
                int *partition,
                showmereal *shift,
                showmereal *dataptr,
                showmereal *datahist,
                showmereal xcenter,
                showmereal ycenter,
                showmereal zcenter,
                showmereal xscale,
                showmereal yscale,
                showmereal xoffset,
                showmereal yoffset)
{
  showmelong i;
  int j, k, l, m;
  int index;
  int faces;
  int tet, face;
  int shade;
  showmereal normx, normy, normz, norm;
  showmereal xshift, yshift, zshift;
  showmereal normalizer;
  showmereal kdatum, ldatum, mdatum;
  showmereal datum0, datum1, datum2, datum3;
  /*
  showmereal lengthkl, lengthkm, lengthlm;
  */
  showmereal *nowpoint;
  XPoint vertices[4];
  struct vec_t corner[4];
  vector_t hpt;
  struct facelist *drawfaces;
  XPoint *store_vertices[4];

  if (!wireframe) {
    drawfaces = (struct facelist *)
                malloc((elems + 1) * 4 * sizeof(struct facelist));
    if (drawfaces == (struct facelist *) NULL) {
      printf("  Insufficient memory to draw object.\n");
      return;
    }
    store_vertices[0] = (XPoint *) malloc((elems + 1) * sizeof(XPoint));
    store_vertices[1] = (XPoint *) malloc((elems + 1) * sizeof(XPoint));
    store_vertices[2] = (XPoint *) malloc((elems + 1) * sizeof(XPoint));
    store_vertices[3] = (XPoint *) malloc((elems + 1) * sizeof(XPoint));
  }

  if (colordisplay && (dataptr != (showmereal *) NULL)) {
    normalizer = 0.999 * (showmereal) MAXCOLORS / (datahist[1] - datahist[0]);
  }

  faces = 0;
  if (wireframe) {
    i = elems;
    while (tetraptr[i].invisible && (i > 0)) {
      i--;
    }
  } else {
    i = tetraptr[0].nexttet;
  }
  while (i != 0) {
    if ((partition != (int *) NULL) && explode) {
      xshift = shift[partition[i] * 3];
      yshift = shift[partition[i] * 3 + 1];
      zshift = shift[partition[i] * 3 + 2];
    }

    index = 4 * i;
    for (j = 0; j < 4; j++) {
      nowpoint = &nodeptr[eleptr[index++] * 3];
      hpt[0] = nowpoint[0] - xcenter;
      hpt[1] = nowpoint[1] - ycenter;
      hpt[2] = nowpoint[2] - zcenter;
      if ((partition != (int *) NULL) && explode) {
        hpt[0] += xshift;
        hpt[1] += yshift;
        hpt[2] += zshift;
      }
      mult_matvec(viewmatrix, hpt, hpt);
/*      perspectiveproj(hpt, &pt1); */

      if (!wireframe) {
        corner[j].x = hpt[0];
        corner[j].y = hpt[1];
        corner[j].z = hpt[2];
        store_vertices[j][i].x = (short) (hpt[0] * xscale + xoffset);
        store_vertices[j][i].y = (short) (hpt[1] * yscale + yoffset);
      } else {
        vertices[j].x = (short) (hpt[0] * xscale + xoffset);
        vertices[j].y = (short) (hpt[1] * yscale + yoffset);
      }
    }

    if (wireframe) {
      if (colordisplay && !fillelem) {
        if (partition != (int *) NULL) {
          XSetForeground(display, linegc,
                         colors[bitreverse[partition[i] & 63]]);
        } else if (dataptr != (showmereal *) NULL) {
          datum0 = dataptr[eleptr[i * 4]];
          datum1 = dataptr[eleptr[i * 4 + 1]];
          datum2 = dataptr[eleptr[i * 4 + 2]];
          datum3 = dataptr[eleptr[i * 4 + 3]];
          XSetForeground(display, linegc,
                         colors[(int) ((0.5 * (datum0 + datum1) - datahist[0])
                                       * normalizer)]);
        }
      }
      XDrawLine(display, mainwindow, linegc, vertices[0].x, vertices[0].y,
                vertices[1].x, vertices[1].y);
      if (colordisplay && !fillelem && (dataptr != (showmereal *) NULL)) {
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (datum1 + datum2) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc, vertices[1].x, vertices[1].y,
                vertices[2].x, vertices[2].y);
      if (colordisplay && !fillelem && (dataptr != (showmereal *) NULL)) {
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (datum2 + datum0) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc, vertices[2].x, vertices[2].y,
                vertices[0].x, vertices[0].y);
      if (colordisplay && !fillelem && (dataptr != (showmereal *) NULL)) {
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (datum0 + datum3) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc, vertices[0].x, vertices[0].y,
                vertices[3].x, vertices[3].y);
      if (colordisplay && !fillelem && (dataptr != (showmereal *) NULL)) {
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (datum1 + datum3) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc, vertices[1].x, vertices[1].y,
                vertices[3].x, vertices[3].y);
      if (colordisplay && !fillelem && (dataptr != (showmereal *) NULL)) {
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (datum2 + datum3) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc, vertices[2].x, vertices[2].y,
                vertices[3].x, vertices[3].y);
      do {
        i--;
      } while (tetraptr[i].invisible && (i > 0));
    } else {
      for (face = 0; face < 4; face++) {
        if (tetraptr[i].neighbor[face] <= 0) {
          k = (face + 1) & 3;
          l = (face + 2) & 3;
          m = (face + 3) & 3;
          normz = (corner[l].x - corner[k].x) * (corner[m].y - corner[k].y) -
                  (corner[l].y - corner[k].y) * (corner[m].x - corner[k].x);
          if ((face == 0) || (face == 2)) {
            normz = - normz;
          }
          if (normz > 0.0) {
            /*
            lengthkl = sqrt((corner[k].x - corner[l].x) *
                            (corner[k].x - corner[l].x) +
                            (corner[k].y - corner[l].y) *
                            (corner[k].y - corner[l].y) +
                            (corner[k].z - corner[l].z) *
                            (corner[k].z - corner[l].z));
            lengthkm = sqrt((corner[k].x - corner[m].x) *
                            (corner[k].x - corner[m].x) +
                            (corner[k].y - corner[m].y) *
                            (corner[k].y - corner[m].y) +
                            (corner[k].z - corner[m].z) *
                            (corner[k].z - corner[m].z));
            lengthlm = sqrt((corner[l].x - corner[m].x) *
                            (corner[l].x - corner[m].x) +
                            (corner[l].y - corner[m].y) *
                            (corner[l].y - corner[m].y) +
                            (corner[l].z - corner[m].z) *
                            (corner[l].z - corner[m].z));
            drawfaces[faces].z = (lengthlm * corner[k].z +
                                  lengthkm * corner[l].z +
                                  lengthkl * corner[m].z) /
                                 (lengthlm + lengthkm +lengthkl);
            */
            drawfaces[faces].z = corner[k].z + corner[l].z + corner[m].z;
            drawfaces[faces].whichtet = i;
            drawfaces[faces].whichface = face;
            normx = (corner[l].y - corner[k].y) * (corner[m].z - corner[k].z) -
                    (corner[l].z - corner[k].z) * (corner[m].y - corner[k].y);
            normy = (corner[l].z - corner[k].z) * (corner[m].x - corner[k].x) -
                    (corner[l].x - corner[k].x) * (corner[m].z - corner[k].z);
            if ((face == 0) || (face == 2)) {
              normx = - normx;
              normy = - normy;
            }
            norm = normx * normx + normy * normy + normz * normz;
            if (norm == 0.0) {
              normx = 0.0;
              normy = 0.0;
              normz = 1.0;
              norm = 1.0;
            } else {
              norm = 1.0 / sqrt(norm);
            }
            shade = (int) ((normx * lightsourcex +
                            normy * lightsourcey +
                            normz * lightsourcez) *
                           norm * (showmereal) MAXGRAYS);
            if (shade < 0) {
              shade = 0;
            } else if (shade >= MAXGRAYS) {
              /* This should never happen. */
              shade = MAXGRAYS - 1;
            }
            drawfaces[faces].color = shade;
            faces++;
          }
        }
      }
      i = tetraptr[i].nexttet;
    }
  }

  if (!wireframe) {
    if (faces > 1) {
      sortfaces(drawfaces, faces);
    }
    for (i = 0; i < faces; i++) {
      tet = drawfaces[i].whichtet;
      face = drawfaces[i].whichface;
      k = (face + 1) & 3;
      l = (face + 2) & 3;
      m = (face + 3) & 3;

      vertices[0].x = store_vertices[k][tet].x;
      vertices[0].y = store_vertices[k][tet].y;
      vertices[1].x = store_vertices[l][tet].x;
      vertices[1].y = store_vertices[l][tet].y;
      vertices[2].x = store_vertices[m][tet].x;
      vertices[2].y = store_vertices[m][tet].y;

      if (colordisplay) {
        if (partition != (int *) NULL) {
          if (fillelem) {
            XSetForeground(display, trianglegc,
                           colors[bitreverse[partition[tet] & 63]]);
          } else {
            XSetForeground(display, linegc,
                           colors[bitreverse[partition[tet] & 63]]);
            XSetForeground(display, trianglegc, grays[drawfaces[i].color]);
          }
        } else if (dataptr != (showmereal *) NULL) {
          kdatum = dataptr[eleptr[tet * 4 + k]];
          ldatum = dataptr[eleptr[tet * 4 + l]];
          mdatum = dataptr[eleptr[tet * 4 + m]];
          if (fillelem) {
            XSetForeground(display, trianglegc,
                           colors[(int) ((ONETHIRD * (kdatum + ldatum + mdatum)
                                          - datahist[0]) * normalizer)]);
            XSetForeground(display, linegc, showme_foreground);
          } else {
            XSetForeground(display, trianglegc, grays[drawfaces[i].color]);
            XSetForeground(display, linegc,
                           colors[(int) ((0.5 * (kdatum + ldatum)
                                          - datahist[0]) * normalizer)]);
          }
        } else {
          XSetForeground(display, trianglegc, grays[drawfaces[i].color]);
        }
      }

      XFillPolygon(display, mainwindow, trianglegc, vertices, 3,
                   Convex, CoordModeOrigin);
      XDrawLine(display, mainwindow, linegc,
                vertices[0].x, vertices[0].y, vertices[1].x, vertices[1].y);
      if (colordisplay && !fillelem && (dataptr != (showmereal *) NULL)) {
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (ldatum + mdatum) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc,
                vertices[1].x, vertices[1].y, vertices[2].x, vertices[2].y);
      if (colordisplay && !fillelem && (dataptr != (showmereal *) NULL)) {
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (mdatum + kdatum) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc,
                vertices[2].x, vertices[2].y, vertices[0].x, vertices[0].y);
      if (colordisplay && (dataptr != (showmereal *) NULL)) {
        XSetForeground(display, linegc,
                       colors[(int) ((kdatum - datahist[0]) * normalizer)]);
        XFillArc(display, mainwindow, linegc,
                 vertices[0].x - 2 - (int) (line_width >> 1),
                 vertices[0].y - 2 - (int) (line_width >> 1),
                 line_width + 4, line_width + 4, 0, 23040);
        XSetForeground(display, linegc,
                       colors[(int) ((ldatum - datahist[0]) * normalizer)]);
        XFillArc(display, mainwindow, linegc,
                 vertices[1].x - 2 - (int) (line_width >> 1),
                 vertices[1].y - 2 - (int) (line_width >> 1),
                 line_width + 4, line_width + 4, 0, 23040);
        XSetForeground(display, linegc,
                       colors[(int) ((mdatum - datahist[0]) * normalizer)]);
        XFillArc(display, mainwindow, linegc,
                 vertices[2].x - 2 - (int) (line_width >> 1),
                 vertices[2].y - 2 - (int) (line_width >> 1),
                 line_width + 4, line_width + 4, 0, 23040);
      }
    }
    free(drawfaces);
    for (i = 0; i < 4; i++) {
      free(store_vertices[i]);
    }
  }
  XSetForeground(display, linegc, showme_foreground);
}

void draw_edge2d(showmelong nodes,
                 showmelong edges,
                 showmereal *nodeptr,
                 showmelong *edgeptr,
                 showmereal *normptr,
                 showmereal xcenter,
                 showmereal ycenter,
                 showmereal xscale,
                 showmereal yscale,
                 showmereal xoffset,
                 showmereal yoffset)
{
  showmelong i;
  showmelong index;
  showmereal *point1, *point2;
  showmereal normx, normy;
  showmereal normmult, normmultx, normmulty;
  showmereal windowxmin, windowymin, windowxmax, windowymax;

  index = 2;
  for (i = 1; i <= edges; i++) {
    point1 = &nodeptr[edgeptr[index++] * 2];
    if (edgeptr[index] == -1) {
      normx = normptr[index - 1];
      normy = normptr[index++];
      normmultx = 0.0;
      if (normx > 0) {
        windowxmax = xcenter + (0.5 * (showmereal) width / xscale);
        normmultx = (windowxmax - point1[0]) / normx;
      } else if (normx < 0) {
        windowxmin = xcenter - (0.5 * (showmereal) width / xscale);
        normmultx = (windowxmin - point1[0]) / normx;
      }
      normmulty = 0.0;
      if (normy > 0) {
        windowymax = ycenter - (0.5 * (showmereal) height / yscale);
        normmulty = (windowymax - point1[1]) / normy;
      } else if (normy < 0) {
        windowymin = ycenter + (0.5 * (showmereal) height / yscale);
        normmulty = (windowymin - point1[1]) / normy;
      }
      if (normmultx == 0.0) {
        normmult = normmulty;
      } else if (normmulty == 0.0) {
        normmult = normmultx;
      } else if (normmultx < normmulty) {
        normmult = normmultx;
      } else {
        normmult = normmulty;
      }
      if (normmult > 0.0) {
        XDrawLine(display, mainwindow, linegc,
                  (int) ((point1[0] - xcenter) * xscale + xoffset),
                  (int) ((point1[1] - ycenter) * yscale + yoffset),
                  (int) ((point1[0] - xcenter + normmult * normx)
                         * xscale + xoffset),
                  (int) ((point1[1] - ycenter + normmult * normy)
                         * yscale + yoffset));
      }
    } else {
      point2 = &nodeptr[edgeptr[index++] * 2];
      XDrawLine(display, mainwindow, linegc,
                (int) ((point1[0] - xcenter) * xscale + xoffset),
                (int) ((point1[1] - ycenter) * yscale + yoffset),
                (int) ((point2[0] - xcenter) * xscale + xoffset),
                (int) ((point2[1] - ycenter) * yscale + yoffset));
    }
  }
}

void draw_edge3d(showmelong nodes,
                 showmelong edges,
                 showmereal *nodeptr,
                 showmelong *edgeptr,
                 showmereal xcenter,
                 showmereal ycenter,
                 showmereal zcenter,
                 showmereal xscale,
                 showmereal yscale,
                 showmereal xoffset,
                 showmereal yoffset)
{
  showmelong i;
  showmelong index;
  showmereal *point1, *point2;
  vector_t hpt1, hpt2;

  index = 2;
  for (i = 1; i <= edges; i++) {
    point1 = &nodeptr[edgeptr[index++] * 3];
    hpt1[0] = point1[0] - xcenter;
    hpt1[1] = point1[1] - ycenter;
    hpt1[2] = point1[2] - zcenter;
    mult_matvec(viewmatrix, hpt1, hpt1);
/*    perspectiveproj(hpt, &pt1); */
    point2 = &nodeptr[edgeptr[index++] * 3];
    hpt2[0] = point2[0] - xcenter;
    hpt2[1] = point2[1] - ycenter;
    hpt2[2] = point2[2] - zcenter;
    mult_matvec(viewmatrix, hpt2, hpt2);
/*    perspectiveproj(hpt, &pt2); */
    XDrawLine(display, mainwindow, linegc,
              (int) (hpt1[0] * xscale + xoffset),
              (int) (hpt1[1] * yscale + yoffset),
              (int) (hpt2[0] * xscale + xoffset),
              (int) (hpt2[1] * yscale + yoffset));
  }
}

void draw_adj2d(int subdomains,
                int *adjptr,
                showmereal *center,
                showmereal xcenter,
                showmereal ycenter,
                showmereal xscale,
                showmereal yscale,
                showmereal xoffset,
                showmereal yoffset)
{
  int i, j;
  showmereal *point1, *point2;

  for (i = 0; i < subdomains; i++) {
    for (j = i + 1; j < subdomains; j++) {
      if (adjptr[i * subdomains + j]) {
        point1 = &center[i * 2];
        point2 = &center[j * 2];
        XDrawLine(display, mainwindow, linegc,
                  (int) ((point1[0] - xcenter) * xscale + xoffset),
                  (int) ((point1[1] - ycenter) * yscale + yoffset),
                  (int) ((point2[0] - xcenter) * xscale + xoffset),
                  (int) ((point2[1] - ycenter) * yscale + yoffset));
      }
    }
  }
  for (i = 0; i < subdomains; i++) {
    point1 = &center[i * 2];
    if (colordisplay) {
      XSetForeground(display, linegc, colors[bitreverse[i & 63]]);
    }
    XFillArc(display, mainwindow, linegc,
             (int) ((point1[0] - xcenter) * xscale + xoffset - 5 -
                    (line_width >> 1)),
             (int) ((point1[1] - ycenter) * yscale + yoffset - 5 -
                    (line_width >> 1)),
             line_width + 10, line_width + 10, 0, 23040);
  }
  XSetForeground(display, linegc, showme_foreground);
}

void draw_adj3d(int subdomains,
                int *adjptr,
                showmereal *center,
                showmereal xcenter,
                showmereal ycenter,
                showmereal zcenter,
                showmereal xscale,
                showmereal yscale,
                showmereal xoffset,
                showmereal yoffset)
{
  int i, j;
  showmereal *point1, *point2;
  vector_t hpt1, hpt2;

  for (i = 0; i < subdomains; i++) {
    for (j = i + 1; j < subdomains; j++) {
      if (adjptr[i * subdomains + j]) {
        point1 = &center[i * 3];
        hpt1[0] = point1[0] - xcenter;
        hpt1[1] = point1[1] - ycenter;
        hpt1[2] = point1[2] - zcenter;
        mult_matvec(viewmatrix, hpt1, hpt1);
/*        perspectiveproj(hpt1, &pt1); */
        point2 = &center[j * 3];
        hpt2[0] = point2[0] - xcenter;
        hpt2[1] = point2[1] - ycenter;
        hpt2[2] = point2[2] - zcenter;
        mult_matvec(viewmatrix, hpt2, hpt2);
/*        perspectiveproj(hpt2, &pt2); */
        XDrawLine(display, mainwindow, linegc,
                  (int) (hpt1[0] * xscale + xoffset),
                  (int) (hpt1[1] * yscale + yoffset),
                  (int) (hpt2[0] * xscale + xoffset),
                  (int) (hpt2[1] * yscale + yoffset));
      }
    }
  }
  for (i = 0; i < subdomains; i++) {
    point1 = &center[i * 3];
    if (colordisplay) {
      XSetForeground(display, linegc, colors[bitreverse[i & 63]]);
    }
    hpt1[0] = point1[0] - xcenter;
    hpt1[1] = point1[1] - ycenter;
    hpt1[2] = point1[2] - zcenter;
    mult_matvec(viewmatrix, hpt1, hpt1);
/*    perspectiveproj(hpt1, &pt1); */
    XFillArc(display, mainwindow, linegc,
             (int) (hpt1[0] * xscale + xoffset - 5 - (line_width >> 1)),
             (int) (hpt1[1] * yscale + yoffset - 5 - (line_width >> 1)),
             line_width + 10, line_width + 10, 0, 23040);
  }
  XSetForeground(display, linegc, showme_foreground);
}

void draw_data2d(showmelong nodes,
                 showmelong elems,
                 showmelong datavalues,
                 showmereal *nodeptr,
                 showmelong *eleptr,
                 showmereal *dataptr,
                 showmereal *datahist,
                 showmereal xcenter,
                 showmereal ycenter,
                 showmereal xscale,
                 showmereal yscale,
                 showmereal xoffset,
                 showmereal yoffset)
{
  showmereal normalizer;
  showmereal datum1, datum2, datum3;
  int shade;
  showmelong i;
  int index;

  showmereal datafac = 20.0 / (datahist[1] - datahist[0]);
  showmereal dataoffset = 0.5 * (datahist[0] + datahist[1]) * datafac;

  showmereal *point1, *point2, *point3;
  vector_t hpt1, hpt2, hpt3;
  showmereal normx, normy, normz, norm;

  struct facelist *drawfaces = (struct facelist *)
                               malloc(elems * sizeof(struct facelist));
  XPoint *vertices = (XPoint *) malloc(sizeof(XPoint) * (elems + 1) * 3);
  XPoint *final;

  if (colordisplay) {
    normalizer = 0.999 * (showmereal) MAXCOLORS / (datahist[1] - datahist[0]);
  }

  index = 3;
  for (i = 1; i <= elems; i++) {
    point1 = &nodeptr[eleptr[index++] * 2];
    point2 = &nodeptr[eleptr[index++] * 2];
    point3 = &nodeptr[eleptr[index++] * 2];

    hpt1[0] = point1[0] - xcenter;
    hpt1[1] = point1[1] - ycenter;
    hpt1[2] = dataptr[eleptr[3 * i]] * datafac - dataoffset;
    mult_matvec(viewmatrix, hpt1, hpt1);
/*    perspectiveproj(hpt1, &pt1); */
    hpt2[0] = point2[0] - xcenter;
    hpt2[1] = point2[1] - ycenter;
    hpt2[2] = dataptr[eleptr[3 * i + 1]] * datafac - dataoffset;
    mult_matvec(viewmatrix, hpt2, hpt2);
/*    perspectiveproj(hpt2, &pt2); */
    hpt3[0] = point3[0] - xcenter;
    hpt3[1] = point3[1] - ycenter;
    hpt3[2] = dataptr[eleptr[3 * i + 2]] * datafac - dataoffset;
    mult_matvec(viewmatrix, hpt3, hpt3);
/*    perspectiveproj(hpt3, &pt3); */

    if (wireframe) {
      if (colordisplay && !fillelem) {
        datum1 = dataptr[eleptr[i * 3]];
        datum2 = dataptr[eleptr[i * 3 + 1]];
        datum3 = dataptr[eleptr[i * 3 + 2]];
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (datum1 + datum2) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc,
                (int) (hpt1[0] * xscale + xoffset),
                (int) (hpt1[1] * yscale + yoffset),
                (int) (hpt2[0] * xscale + xoffset),
                (int) (hpt2[1] * yscale + yoffset));
      if (colordisplay && !fillelem) {
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (datum2 + datum3) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc,
                (int) (hpt2[0] * xscale + xoffset),
                (int) (hpt2[1] * yscale + yoffset),
                (int) (hpt3[0] * xscale + xoffset),
                (int) (hpt3[1] * yscale + yoffset));
      if (colordisplay && !fillelem) {
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (datum3 + datum1) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc,
                (int) (hpt3[0] * xscale + xoffset),
                (int) (hpt3[1] * yscale + yoffset),
                (int) (hpt1[0] * xscale + xoffset),
                (int) (hpt1[1] * yscale + yoffset));
    } else {
      vertices[3 * i].x = (short) (hpt1[0] * xscale + xoffset);
      vertices[3 * i].y = (short) (hpt1[1] * yscale + yoffset);
      vertices[3 * i + 1].x = (short) (hpt2[0] * xscale + xoffset);
      vertices[3 * i + 1].y = (short) (hpt2[1] * yscale + yoffset);
      vertices[3 * i + 2].x = (short) (hpt3[0] * xscale + xoffset);
      vertices[3 * i + 2].y = (short) (hpt3[1] * yscale + yoffset);

      drawfaces[i - 1].whichtet = i;
      drawfaces[i - 1].z = hpt1[2] + hpt2[2] + hpt3[2];
      normx = (hpt2[1] - hpt1[1]) * (hpt3[2] - hpt1[2])
            - (hpt2[2] - hpt1[2]) * (hpt3[1] - hpt1[1]);
      normy = (hpt2[2] - hpt1[2]) * (hpt3[0] - hpt1[0])
            - (hpt2[0] - hpt1[0]) * (hpt3[2] - hpt1[2]);
      normz = (hpt2[0] - hpt1[0]) * (hpt3[1] - hpt1[1])
            - (hpt2[1] - hpt1[1]) * (hpt3[0] - hpt1[0]);
      norm = normx * normx + normy * normy + normz * normz;
      if (norm == 0.0) {
        normx = 0.0;
        normy = 0.0;
        normz = 1.0;
        norm = 1.0;
      } else {
        norm = 1.0 / sqrt(norm);
      }
      if (normz < 0.0) {
        normx = -normx;
        normy = -normy;
        normz = -normz;
      }
      shade = (int) ((normx * lightsourcex +
                      normy * lightsourcey +
                      normz * lightsourcez) * norm * (showmereal) MAXGRAYS);
      if (shade < 0) {
        shade = 0;
      } else if (shade >= MAXGRAYS) {
        /* This should never happen. */
        shade = MAXGRAYS - 1;
      }
      drawfaces[i - 1].color = shade;
    }
  }

  if (!wireframe) {
    if (elems > 1) {
      sortfaces(drawfaces, elems);
    }
    for (i = 1; i <= elems; i++) {
      final = &vertices[3 * drawfaces[i - 1].whichtet];

      if (colordisplay) {
        datum1 = dataptr[eleptr[drawfaces[i - 1].whichtet * 3]];
        datum2 = dataptr[eleptr[drawfaces[i - 1].whichtet * 3 + 1]];
        datum3 = dataptr[eleptr[drawfaces[i - 1].whichtet * 3 + 2]];
        if (fillelem) {
          XSetForeground(display, trianglegc,
                         colors[(int) ((ONETHIRD * (datum1 + datum2 + datum3)
                                        - datahist[0]) * normalizer)]);
          XSetForeground(display, linegc, showme_foreground);	
        } else {
          XSetForeground(display, trianglegc, grays[drawfaces[i - 1].color]);
          XSetForeground(display, linegc,
                         colors[(int) ((0.5 * (datum1 + datum2) - datahist[0])
                                       * normalizer)]);
        }
      }
      XFillPolygon(display, mainwindow, trianglegc, final, 3,
                   Convex, CoordModeOrigin);

      /* outline the solid polygons */
      XDrawLine(display, mainwindow, linegc,
                final[0].x, final[0].y, final[1].x, final[1].y);
      if (colordisplay && !fillelem) {
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (datum2 + datum3) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc,
                final[1].x, final[1].y, final[2].x, final[2].y);
      if (colordisplay && !fillelem) {
        XSetForeground(display, linegc,
                       colors[(int) ((0.5 * (datum3 + datum1) - datahist[0])
                                     * normalizer)]);
      }
      XDrawLine(display, mainwindow, linegc,
                final[2].x, final[2].y, final[0].x, final[0].y);
      if (colordisplay) {
        XSetForeground(display, linegc,
                       colors[(int) ((datum1 - datahist[0]) * normalizer)]);
        XFillArc(display, mainwindow, linegc,
                 final[0].x - 2 - (int) (line_width >> 1),
                 final[0].y - 2 - (int) (line_width >> 1),
                 line_width + 4, line_width + 4, 0, 23040);
        XSetForeground(display, linegc,
                       colors[(int) ((datum2 - datahist[0]) * normalizer)]);
        XFillArc(display, mainwindow, linegc,
                 final[1].x - 2 - (int) (line_width >> 1),
                 final[1].y - 2 - (int) (line_width >> 1),
                 line_width + 4, line_width + 4, 0, 23040);
        XSetForeground(display, linegc,
                       colors[(int) ((datum3 - datahist[0]) * normalizer)]);
        XFillArc(display, mainwindow, linegc,
                 final[2].x - 2 - (int) (line_width >> 1),
                 final[2].y - 2 - (int) (line_width >> 1),
                 line_width + 4, line_width + 4, 0, 23040);
      }
    }
  }
  XSetForeground(display, linegc, showme_foreground);
}

void draw_image(int inc,
                int image,
                showmereal xcenter,
                showmereal ycenter,
                showmereal zcenter,
                showmereal xwidth,
                showmereal ywidth,
                showmereal xtrans,
                showmereal ytrans)
{
  XClearWindow(display, mainwindow);
  if (image == NOTHING) {
    return;
  }
  if (!loaded[inc][image]) {
    return;
  }
  if ((image == PART) && explode) {
    xwidth *= (1.0 + explosion);
    ywidth *= (1.0 + explosion);
  }
  xscale = (showmereal) (width - line_width - 4) / xwidth;
  yscale = (showmereal) (height - line_width - 4) / ywidth;
  if (xscale > yscale) {
    xscale = yscale;
  } else {
    yscale = xscale;
  }
  yscale = -yscale;

  xoffset = 0.5 * (showmereal) width + xtrans * xscale;
  yoffset = 0.5 * (showmereal) height + ytrans * yscale;
  perspdistance = xwidth * perspfactor;

  switch (image) {
    case NODE:
      if (nodedim[inc] == 2) {
        draw_node2d(nodes[inc], nodeptr[inc], xcenter, ycenter,
                    xscale, yscale, xoffset, yoffset);
      } else {
        draw_node3d(nodes[inc], nodeptr[inc], xcenter, ycenter, zcenter,
                    xscale, yscale, xoffset, yoffset);
      }
      break;
    case POLY:
      if (polynodes[inc] > 0) {
        if (polydim[inc] == 2) {
          draw_poly2d(polynodes[inc], polyedges[inc], polyholes[inc],
                      polynodeptr[inc], polysegptr[inc], polyholeptr[inc],
                      xcenter, ycenter, xscale, yscale, xoffset, yoffset);
        }
      } else {
        if (nodedim[inc] == 2) {
          draw_poly2d(nodes[inc], polyedges[inc], polyholes[inc],
                      nodeptr[inc], polysegptr[inc], polyholeptr[inc],
                      xcenter, ycenter, xscale, yscale, xoffset, yoffset);
        }
      }
      break;
    case ELE:
      if (nodedim[inc] == 2) {
        draw_ele2d(elems[inc], nodeptr[inc], eleptr[inc],
                   (int *) NULL, (showmereal *) NULL, xcenter, ycenter,
                   xscale, yscale, xoffset, yoffset);
      } else {
        draw_ele3d(elems[inc], nodeptr[inc], eleptr[inc],
                   (int *) NULL, (showmereal *) NULL, (showmereal *) NULL, (showmereal *) NULL,
                   xcenter, ycenter, zcenter, xscale, yscale,
                   xoffset, yoffset);
      }
      break;
    case EDGE:
      if (nodedim[inc] == 2) {
        draw_edge2d(nodes[inc], edges[inc], nodeptr[inc],
                    edgeptr[inc], normptr[inc], xcenter, ycenter,
                    xscale, yscale, xoffset, yoffset);
      } else {
        draw_edge3d(nodes[inc], edges[inc], nodeptr[inc],
                    edgeptr[inc], xcenter, ycenter, zcenter,
                    xscale, yscale, xoffset, yoffset);
      }
      break;
    case PART:
      if (nodedim[inc] == 2) {
        draw_ele2d(elems[inc], nodeptr[inc], eleptr[inc],
                   partition[inc], subdomshift[inc], xcenter, ycenter,
                   xscale, yscale, xoffset, yoffset);
      } else {
        draw_ele3d(elems[inc], nodeptr[inc], eleptr[inc],
                   partition[inc], subdomshift[inc],
                   (showmereal *) NULL, (showmereal *) NULL,
                   xcenter, ycenter, zcenter, xscale, yscale,
                   xoffset, yoffset);
      }
      break;
    case ADJ:
      if (nodedim[inc] == 2) {
        draw_adj2d(adjsubdomains[inc], adjptr[inc], subdomcenter[inc],
                   xcenter, ycenter, xscale, yscale, xoffset, yoffset);
      } else {
        draw_adj3d(adjsubdomains[inc], adjptr[inc], subdomcenter[inc],
                   xcenter, ycenter, zcenter, xscale, yscale,
                   xoffset, yoffset);
      }
      break;
    case VORO:
      if (vnodedim[inc] == 2) {
        if (loaded[inc][NODE]) {
          if (nodedim[inc] == 2) {
            draw_node2d(nodes[inc], nodeptr[inc], xcenter, ycenter,
                        xscale, yscale, xoffset, yoffset);
          }
        }
        draw_edge2d(vnodes[inc], vedges[inc], vnodeptr[inc],
                    vedgeptr[inc], vnormptr[inc],
                    xcenter, ycenter, xscale, yscale, xoffset, yoffset);
      }
      break;
    case DATA:
      if (nodedim[inc] == 2) {
        draw_data2d(nodes[inc], elems[inc], datavalues[inc],
                    nodeptr[inc], eleptr[inc], dataptr[inc], datahist[inc],
                    xcenter, ycenter, xscale, yscale, xoffset, yoffset);
      } else {
        draw_ele3d(elems[inc], nodeptr[inc], eleptr[inc],
                   (int *) NULL, (showmereal *) NULL,
                   dataptr[inc], datahist[inc],
                   xcenter, ycenter, zcenter, xscale, yscale,
                   xoffset, yoffset);
      }
      break;
    default:
      break;
  }
}

void addps(char *instring,
           char *outstring,
           int eps)
{
  strcpy(outstring, instring);
  if (eps) {
    strcat(outstring, ".eps");
  } else {
    strcat(outstring, ".ps");
  }
}

int print_head(char *fname,
               FILE **file,
               int llcornerx,
               int llcornery,
               int eps)
{
  if (!quiet) {
    printf("Writing %s\n", fname);
  }
  *file = fopen(fname, "w");
  if (*file == (FILE *) NULL) {
    printf("  Error:  Could not open %s\n", fname);
    return 1;
  }
  if (eps) {
    fprintf(*file, "%%!PS-Adobe-2.0 EPSF-2.0\n");
  } else {
    fprintf(*file, "%%!PS-Adobe-2.0\n");
  }
  fprintf(*file, "%%%%BoundingBox: %d %d %d %d\n", llcornerx, llcornery,
          612 - llcornerx, 792 - llcornery);
  fprintf(*file, "%%%%Creator: Show Me\n");
  fprintf(*file, "%%%%EndComments\n\n");
  fprintf(*file, "/m {moveto} bind def\n");
  fprintf(*file, "/l {lineto} bind def\n");
  fprintf(*file, "/s {setrgbcolor} bind def\n");
  fprintf(*file, "/g {gsave fill grestore} bind def\n");
  fprintf(*file, "/k {stroke} bind def\n\n");
  fprintf(*file, "1 setlinecap\n");
  fprintf(*file, "1 setlinejoin\n");
  fprintf(*file, "%f setlinewidth\n", 0.3 * (double) line_width);
  fprintf(*file, "%d %d m\n", llcornerx, llcornery);
  fprintf(*file, "%d %d l\n", 612 - llcornerx, llcornery);
  fprintf(*file, "%d %d l\n", 612 - llcornerx, 792 - llcornery);
  fprintf(*file, "%d %d l\n", llcornerx, 792 - llcornery);
  fprintf(*file, "closepath\nclip\nnewpath\n");
  return 0;
}

void print_node2d(FILE *nodefile,
                  showmelong nodes,
                  showmereal *nodeptr,
                  showmereal xcenter,
                  showmereal ycenter,
                  showmereal xscale,
                  showmereal yscale,
                  showmereal xoffset,
                  showmereal yoffset)
{
  showmelong i;
  showmelong index;

  index = 2;
  for (i = 1; i <= nodes; i++) {
    fprintf(nodefile, "%f %f %d 0 360 arc\nfill\n",
            (nodeptr[index] - xcenter) * xscale + xoffset,
            (nodeptr[index + 1] - ycenter) * yscale + yoffset,
            1 + (line_width >> 1));
    index += 2;
  }
}

void print_node3d(FILE *nodefile,
                  showmelong nodes,
                  showmereal *nodeptr,
                  showmereal xcenter,
                  showmereal ycenter,
                  showmereal zcenter,
                  showmereal xscale,
                  showmereal yscale,
                  showmereal xoffset,
                  showmereal yoffset)
{
  showmelong i;
  showmelong index;
  vector_t hpt;

  index = 3;
  for (i = 1; i <= nodes; i++) {
    hpt[0] = nodeptr[index++] - xcenter;
    hpt[1] = nodeptr[index++] - ycenter;
    hpt[2] = nodeptr[index++] - zcenter;
    mult_matvec(viewmatrix, hpt, hpt);
/*    perspectiveproj(hpt, &pt1); */
    fprintf(nodefile, "%f %f %d 0 360 arc\nfill\n",
            hpt[0] * xscale + xoffset, hpt[1] * yscale + yoffset,
            1 + (line_width >> 1));
  }
}

void print_poly2d(FILE *polyfile,
                  showmelong nodes,
                  showmelong edges,
                  showmereal *nodeptr,
                  showmelong *edgeptr,
                  showmereal xcenter,
                  showmereal ycenter,
                  showmereal xscale,
                  showmereal yscale,
                  showmereal xoffset,
                  showmereal yoffset)
{
  showmereal *point1, *point2;
  showmelong i;
  showmelong index;

  index = 2;
  for (i = 1; i <= nodes; i++) {
    fprintf(polyfile, "%f %f %d 0 360 arc\nfill\n",
            (nodeptr[index] - xcenter) * xscale + xoffset,
            (nodeptr[index + 1] - ycenter) * yscale + yoffset,
            1 + (line_width >> 1));
    index += 2;
  }
  index = 2;
  for (i = 1; i <= edges; i++) {
    point1 = &nodeptr[edgeptr[index++] * 2];
    point2 = &nodeptr[edgeptr[index++] * 2];
    fprintf(polyfile, "%f %f m\n",
            (point1[0] - xcenter) * xscale + xoffset,
            (point1[1] - ycenter) * yscale + yoffset);
    fprintf(polyfile, "%f %f l\nk\n",
            (point2[0] - xcenter) * xscale + xoffset,
            (point2[1] - ycenter) * yscale + yoffset);
  }
  index = 2;
}

void print_ele2d(FILE *elefile,
                 showmelong elems,
                 showmereal *nodeptr,
                 showmelong *eleptr,
                 int *partition,
                 showmereal *shift,
                 showmereal xcenter,
                 showmereal ycenter,
                 showmereal xscale,
                 showmereal yscale,
                 showmereal xoffset,
                 showmereal yoffset,
                 int llcornerx,
                 int llcornery)
{
  showmereal xshift, yshift;
  showmereal *nowpoint;
  int colorindex;
  int index;
  showmelong i;
  int j;

  if ((partition != (int *) NULL) && !bw_ps) {
    fprintf(elefile, "0 0 0 s\n");
    fprintf(elefile, "%d %d m\n", llcornerx, llcornery);
    fprintf(elefile, "%d %d l\n", 612 - llcornerx, llcornery);
    fprintf(elefile, "%d %d l\n", 612 - llcornerx, 792 - llcornery);
    fprintf(elefile, "%d %d l\n", llcornerx, 792 - llcornery);
    fprintf(elefile, "fill\n");
  }
  index = 3;
  for (i = 1; i <= elems; i++) {
    if ((partition != (int *) NULL) && !bw_ps) {
      colorindex = bitreverse[partition[i] & 63];
      fprintf(elefile, "%6.3f %6.3f %6.3f s\n",
              (showmereal) rgb[colorindex].red / 65535.0,
              (showmereal) rgb[colorindex].green / 65535.0,
              (showmereal) rgb[colorindex].blue / 65535.0);
    }
    nowpoint = &nodeptr[eleptr[index + 2] * 2];
    if ((partition != (int *) NULL) && (explode || bw_ps)) {
      xshift = shift[partition[i] << 1];
      yshift = shift[(partition[i] << 1) + 1];
      fprintf(elefile, "%f %f m\n",
              (nowpoint[0] - xcenter + xshift) * xscale + xoffset,
              (nowpoint[1] - ycenter + yshift) * yscale + yoffset);
      for (j = 0; j < 3; j++) {
        nowpoint = &nodeptr[eleptr[index++] * 2];
        fprintf(elefile, "%f %f l\n",
                (nowpoint[0] - xcenter + xshift) * xscale + xoffset,
                (nowpoint[1] - ycenter + yshift) * yscale + yoffset);
      }
    } else {
      fprintf(elefile, "%f %f m\n",
              (nowpoint[0] - xcenter) * xscale + xoffset,
              (nowpoint[1] - ycenter) * yscale + yoffset);
      for (j = 0; j < 3; j++) {
        nowpoint = &nodeptr[eleptr[index++] * 2];
        fprintf(elefile, "%f %f l\n",
                (nowpoint[0] - xcenter) * xscale + xoffset,
                (nowpoint[1] - ycenter) * yscale + yoffset);
      }
    }
    if (fillelem && !bw_ps && (partition != (int *) NULL)) {
      fprintf(elefile, "g\n1 1 0 s\n");
    }
    fprintf(elefile, "k\n");
  }
}

void print_ele3d(FILE *elefile,
                 showmelong elems,
                 showmereal *nodeptr,
                 showmelong *eleptr,
                 int *partition,
                 showmereal *shift,
                 showmereal xcenter,
                 showmereal ycenter,
                 showmereal zcenter,
                 showmereal xscale,
                 showmereal yscale,
                 showmereal xoffset,
                 showmereal yoffset,
                 int llcornerx,
                 int llcornery)
{
  showmelong i;
  int j, k, l, m;
  int index;
  int faces;
  int tet, face;
  int shade;
  int colorindex;
  showmereal normx, normy, normz, norm;
  showmereal xshift, yshift, zshift;
  showmereal *nowpoint;
  struct vec_t vertices[4];
  struct vec_t corner[4];
  vector_t hpt;
  struct facelist *drawfaces;

  struct vec_t *store_vertices[4];

  if (!wireframe) {
    drawfaces = (struct facelist *)
                malloc((elems + 1) * 4 * sizeof(struct facelist));
    if (drawfaces == (struct facelist *) NULL) {
      printf("  Insufficient memory to draw object.\n");
      return;
    }
    store_vertices[0] = (struct vec_t *) malloc((elems + 1)
                                                * sizeof(struct vec_t));
    store_vertices[1] = (struct vec_t *) malloc((elems + 1)
                                                * sizeof(struct vec_t));
    store_vertices[2] = (struct vec_t *) malloc((elems + 1)
                                                * sizeof(struct vec_t));
    store_vertices[3] = (struct vec_t *) malloc((elems + 1)
                                                * sizeof(struct vec_t));
  }

  faces = 0;
  if (wireframe) {
    i = elems;
    while (tetraptr[i].invisible && (i > 0)) {
      i--;
    }
  } else {
    i = tetraptr[0].nexttet;
  }
  while (i != 0) {
    if ((partition != (int *) NULL) && explode) {
      xshift = shift[partition[i] * 3];
      yshift = shift[partition[i] * 3 + 1];
      zshift = shift[partition[i] * 3 + 2];
    }

    index = 4 * i;
    for (j = 0; j < 4; j++) {
      nowpoint = &nodeptr[eleptr[index++] * 3];
      hpt[0] = nowpoint[0] - xcenter;
      hpt[1] = nowpoint[1] - ycenter;
      hpt[2] = nowpoint[2] - zcenter;
      if ((partition != (int *) NULL) && explode) {
        hpt[0] += xshift;
        hpt[1] += yshift;
        hpt[2] += zshift;
      }
      mult_matvec(viewmatrix, hpt, hpt);
/*      perspectiveproj(hpt, &pt1); */

      if (wireframe) {
        vertices[j].x = hpt[0] * xscale + xoffset;
        vertices[j].y = hpt[1] * yscale + yoffset;
      } else {
        corner[j].x = hpt[0];
        corner[j].y = hpt[1];
        corner[j].z = hpt[2];
        store_vertices[j][i].x = hpt[0] * xscale + xoffset;
        store_vertices[j][i].y = hpt[1] * yscale + yoffset;
      }
    }

    if (wireframe) {
      if (!fillelem && !bw_ps && (partition != (int *) NULL)) {
        colorindex = partition[i] & 63;
        fprintf(elefile, "%6.3f %6.3f %6.3f s\n",
                (showmereal) rgb[colorindex].red / 65535.0,
                (showmereal) rgb[colorindex].green / 65535.0,
                (showmereal) rgb[colorindex].blue / 65535.0);
      }
      fprintf(elefile, "%f %f m\n", vertices[0].x, vertices[0].y);
      fprintf(elefile, "%f %f l\n", vertices[1].x, vertices[1].y);
      fprintf(elefile, "%f %f l\n", vertices[2].x, vertices[2].y);
      fprintf(elefile, "%f %f l\n", vertices[0].x, vertices[0].y);
      fprintf(elefile, "%f %f l\n", vertices[3].x, vertices[3].y);
      fprintf(elefile, "%f %f l\nk\n", vertices[1].x, vertices[1].y);
      fprintf(elefile, "%f %f m\n", vertices[2].x, vertices[2].y);
      fprintf(elefile, "%f %f l\nk\n", vertices[3].x, vertices[3].y);
      do {
        i--;
      } while (tetraptr[i].invisible && (i > 0));
    } else {
      for (face = 0; face < 4; face++) {
        if (tetraptr[i].neighbor[face] <= 0) {
          k = (face + 1) & 3;
          l = (face + 2) & 3;
          m = (face + 3) & 3;
          normz = (corner[l].x - corner[k].x) * (corner[m].y - corner[k].y) -
                  (corner[l].y - corner[k].y) * (corner[m].x - corner[k].x);
          if ((face == 0) || (face == 2)) {
            normz = - normz;
          }
          if (normz > 0.0) {
            drawfaces[faces].z = corner[k].z + corner[l].z + corner[m].z;
            drawfaces[faces].whichtet = i;
            drawfaces[faces].whichface = face;
            normx = (corner[l].y - corner[k].y) * (corner[m].z - corner[k].z) -
                    (corner[l].z - corner[k].z) * (corner[m].y - corner[k].y);
            normy = (corner[l].z - corner[k].z) * (corner[m].x - corner[k].x) -
                    (corner[l].x - corner[k].x) * (corner[m].z - corner[k].z);
            if ((face == 0) || (face == 2)) {
              normx = - normx;
              normy = - normy;
            }
            norm = normx * normx + normy * normy + normz * normz;
            if (norm == 0.0) {
              normx = 0.0;
              normy = 0.0;
              normz = 1.0;
              norm = 1.0;
            } else {
              norm = 1.0 / sqrt(norm);
            }
            shade = 16384 + (int) ((normx * lightsourcex +
                                    normy * lightsourcey +
                                    normz * lightsourcez) * norm * 49152.0);
            if (shade < 16384) {
              shade = 16384;
            } else if (shade >= 65536) {
              /* This should never happen. */
              shade = 65535;
            }
            drawfaces[faces].color = shade;
            faces++;
          }
        }
      }
      i = tetraptr[i].nexttet;
    }
  }

  if (!wireframe) {
    if (faces > 1) {
      sortfaces(drawfaces, faces);
    }
    for (i = 0; i < faces; i++) {
      tet = drawfaces[i].whichtet;
      face = drawfaces[i].whichface;
      k = (face + 1) & 3;
      l = (face + 2) & 3;
      m = (face + 3) & 3;

      if (fillelem && !bw_ps && (partition != (int *) NULL)) {
        colorindex = partition[tet] & 63;
        fprintf(elefile, "%6.3f %6.3f %6.3f s\n",
                (showmereal) rgb[colorindex].red / 65535.0,
                (showmereal) rgb[colorindex].green / 65535.0,
                (showmereal) rgb[colorindex].blue / 65535.0);
      } else if (tetraptr[tet].neighbor[face] < 0) {
        fprintf(elefile, "%6.3f %6.3f %6.3f s\n",
                (showmereal) drawfaces[i].color / 65535.0,
                (showmereal) drawfaces[i].color / 65535.0,
                (showmereal) drawfaces[i].color / 65535.0 / 1.5);
        /*
        fprintf(elefile, "%6.3f %6.3f %6.3f s\n",
                1.0,
                1.0,
                (showmereal) drawfaces[i].color / 65535.0);
        */
      } else {
        fprintf(elefile, "%6.3f %6.3f %6.3f s\n",
                (showmereal) drawfaces[i].color / 65535.0 / 1.35,
                (showmereal) drawfaces[i].color / 65535.0,
                (showmereal) drawfaces[i].color / 65535.0 / 1.35);
        /*
        fprintf(elefile, "%6.3f %6.3f %6.3f s\n",
                (showmereal) drawfaces[i].color / 65535.0,
                1.0,
                (showmereal) drawfaces[i].color / 65535.0);
        */
      }
      fprintf(elefile, "%f %f m\n",
              store_vertices[k][tet].x, store_vertices[k][tet].y);
      fprintf(elefile, "%f %f l\n",
              store_vertices[l][tet].x, store_vertices[l][tet].y);
      fprintf(elefile, "%f %f l\n",
              store_vertices[m][tet].x, store_vertices[m][tet].y);
      fprintf(elefile, "%f %f l\n",
              store_vertices[k][tet].x, store_vertices[k][tet].y);
      fprintf(elefile, "g\n\n");
      if (bw_ps) {
        fprintf(elefile, "0 0 0 s\n");
      } else if (!fillelem && (partition != (int *) NULL)) {
        colorindex = partition[tet] & 63;
        fprintf(elefile, "%6.3f %6.3f %6.3f s\n",
                (showmereal) rgb[colorindex].red / 65535.0,
                (showmereal) rgb[colorindex].green / 65535.0,
                (showmereal) rgb[colorindex].blue / 65535.0);
      } else {
        /* Was light green
           fprintf(elefile, "0.3 1 0.3 s\n"); */
        fprintf(elefile, "0 0 0 s\n");
      }
      fprintf(elefile, "k\n");
    }
    free(drawfaces);
    for (i = 0; i < 4; i++) {
      free(store_vertices[i]);
    }
  }
}

void print_edge2d(FILE *edgefile,
                  showmelong nodes,
                  showmelong edges,
                  showmereal *nodeptr,
                  showmelong *edgeptr,
                  showmereal *normptr,
                  showmereal xcenter,
                  showmereal ycenter,
                  showmereal xscale,
                  showmereal yscale,
                  showmereal xoffset,
                  showmereal yoffset,
                  int llcornerx,
                  int llcornery)
{
  showmelong i;
  showmelong index;
  showmereal *point1, *point2;
  showmereal normx, normy;
  showmereal normmult, normmultx, normmulty;
  showmereal windowxmin, windowymin, windowxmax, windowymax;

  index = 2;
  for (i = 1; i <= edges; i++) {
    point1 = &nodeptr[edgeptr[index++] * 2];
    if (edgeptr[index] == -1) {
      normx = normptr[index - 1];
      normy = normptr[index++];
      normmultx = 0.0;
      if (normx > 0) {
        windowxmax = xcenter + ((showmereal) (306 - llcornerx) / xscale);
        normmultx = (windowxmax - point1[0]) / normx;
      } else if (normx < 0) {
        windowxmin = xcenter - ((showmereal) (306 - llcornerx) / xscale);
        normmultx = (windowxmin - point1[0]) / normx;
      }
      normmulty = 0.0;
      if (normy > 0) {
        windowymax = ycenter + ((showmereal) (396 - llcornery) / yscale);
        normmulty = (windowymax - point1[1]) / normy;
      } else if (normy < 0) {
        windowymin = ycenter - ((showmereal) (396 - llcornery) / yscale);
        normmulty = (windowymin - point1[1]) / normy;
      }
      if (normmultx == 0.0) {
        normmult = normmulty;
      } else if (normmulty == 0.0) {
        normmult = normmultx;
      } else if (normmultx < normmulty) {
        normmult = normmultx;
      } else {
        normmult = normmulty;
      }
      if (normmult > 0.0) {
        fprintf(edgefile, "%f %f m\n",
                (point1[0] - xcenter) * xscale + xoffset,
                (point1[1] - ycenter) * yscale + yoffset);
        fprintf(edgefile, "%f %f l\nk\n",
                (point1[0] - xcenter + normmult * normx) * xscale + xoffset,
                (point1[1] - ycenter + normmult * normy) * yscale + yoffset);
      }
    } else {
      point2 = &nodeptr[edgeptr[index++] * 2];
      fprintf(edgefile, "%f %f m\n",
              (point1[0] - xcenter) * xscale + xoffset,
              (point1[1] - ycenter) * yscale + yoffset);
      fprintf(edgefile, "%f %f l\nk\n",
              (point2[0] - xcenter) * xscale + xoffset,
              (point2[1] - ycenter) * yscale + yoffset);
    }
  }
}

void print_edge3d(FILE *edgefile,
                  showmelong nodes,
                  showmelong edges,
                  showmereal *nodeptr,
                  showmelong *edgeptr,
                  showmereal xcenter,
                  showmereal ycenter,
                  showmereal zcenter,
                  showmereal xscale,
                  showmereal yscale,
                  showmereal xoffset,
                  showmereal yoffset,
                  int llcornerx,
                  int llcornery)
{
  showmelong i;
  showmelong index;
  showmereal *point1, *point2;
  vector_t hpt1, hpt2;

  index = 2;
  for (i = 1; i <= edges; i++) {
    point1 = &nodeptr[edgeptr[index++] * 3];
    hpt1[0] = point1[0] - xcenter;
    hpt1[1] = point1[1] - ycenter;
    hpt1[2] = point1[2] - zcenter;
    mult_matvec(viewmatrix, hpt1, hpt1);
/*    perspectiveproj(hpt1, &pt1); */
    point2 = &nodeptr[edgeptr[index++] * 3];
    hpt2[0] = point2[0] - xcenter;
    hpt2[1] = point2[1] - ycenter;
    hpt2[2] = point2[2] - zcenter;
    mult_matvec(viewmatrix, hpt2, hpt2);
/*     perspectiveproj(hpt2, &pt2); */
    fprintf(edgefile, "%f %f m\n",
            hpt1[0] * xscale + xoffset, hpt1[1] * yscale + yoffset);
    fprintf(edgefile, "%f %f l\nk\n",
            hpt2[0] * xscale + xoffset, hpt2[1] * yscale + yoffset);
  }
}

void print_adj2d(FILE *adjfile,
                 int subdomains,
                 int *adjptr,
                 showmereal *center,
                 showmereal xcenter,
                 showmereal ycenter,
                 showmereal xscale,
                 showmereal yscale,
                 showmereal xoffset,
                 showmereal yoffset,
                 int llcornerx,
                 int llcornery)
{
  int i, j;
  showmereal *point1, *point2;
  int colorindex;

  if (!bw_ps) {
    fprintf(adjfile, "0 0 0 s\n");
    fprintf(adjfile, "%d %d m\n", llcornerx, llcornery);
    fprintf(adjfile, "%d %d l\n", 612 - llcornerx, llcornery);
    fprintf(adjfile, "%d %d l\n", 612 - llcornerx, 792 - llcornery);
    fprintf(adjfile, "%d %d l\n", llcornerx, 792 - llcornery);
    fprintf(adjfile, "fill\n");
    fprintf(adjfile, "1 1 0 s\n");
  }
  for (i = 0; i < subdomains; i++) {
    for (j = i + 1; j < subdomains; j++) {
      if (adjptr[i * subdomains + j]) {
        point1 = &center[i * 2];
        point2 = &center[j * 2];
        fprintf(adjfile, "%f %f m\n",
                (point1[0] - xcenter) * xscale + xoffset,
                (point1[1] - ycenter) * yscale + yoffset);
        fprintf(adjfile, "%f %f l\nk\n",
                (point2[0] - xcenter) * xscale + xoffset,
                (point2[1] - ycenter) * yscale + yoffset);
      }
    }
  }
  for (i = 0; i < subdomains; i++) {
    point1 = &center[i * 2];
    if (!bw_ps) {
      colorindex = i & 63;
      fprintf(adjfile, "%6.3f %6.3f %6.3f s\n",
              (showmereal) rgb[colorindex].red / 65535.0,
              (showmereal) rgb[colorindex].green / 65535.0,
              (showmereal) rgb[colorindex].blue / 65535.0);
      fprintf(adjfile, "%f %f %d 0 360 arc\nfill\n",
              (point1[0] - xcenter) * xscale + xoffset,
              (point1[1] - ycenter) * yscale + yoffset,
              5 + (line_width >> 1));
    } else {
      fprintf(adjfile, "%f %f %d 0 360 arc\nfill\n",
              (point1[0] - xcenter) * xscale + xoffset,
              (point1[1] - ycenter) * yscale + yoffset,
              3 + (line_width >> 1));
    }
  }
}

void print_adj3d(FILE *adjfile,
                 int subdomains,
                 int *adjptr,
                 showmereal *center,
                 showmereal xcenter,
                 showmereal ycenter,
                 showmereal zcenter,
                 showmereal xscale,
                 showmereal yscale,
                 showmereal xoffset,
                 showmereal yoffset,
                 int llcornerx,
                 int llcornery)
{
  int i, j;
  showmereal *point1, *point2;
  int colorindex;
  vector_t hpt1, hpt2;

  if (!bw_ps) {
    fprintf(adjfile, "0 0 0 s\n");
    fprintf(adjfile, "%d %d m\n", llcornerx, llcornery);
    fprintf(adjfile, "%d %d l\n", 612 - llcornerx, llcornery);
    fprintf(adjfile, "%d %d l\n", 612 - llcornerx, 792 - llcornery);
    fprintf(adjfile, "%d %d l\n", llcornerx, 792 - llcornery);
    fprintf(adjfile, "fill\n");
    fprintf(adjfile, "1 1 0 s\n");
  }
  for (i = 0; i < subdomains; i++) {
    for (j = i + 1; j < subdomains; j++) {
      if (adjptr[i * subdomains + j]) {
        point1 = &center[i * 3];
        hpt1[0] = point1[0] - xcenter;
        hpt1[1] = point1[1] - ycenter;
        hpt1[2] = point1[2] - zcenter;
        mult_matvec(viewmatrix, hpt1, hpt1);
/*        perspectiveproj(hpt1, &pt1); */
        point2 = &center[j * 3];
        hpt2[0] = point2[0] - xcenter;
        hpt2[1] = point2[1] - ycenter;
        hpt2[2] = point2[2] - zcenter;
        mult_matvec(viewmatrix, hpt2, hpt2);
/*        perspectiveproj(hpt2, &pt2); */
        fprintf(adjfile, "%f %f m\n",
                hpt1[0] * xscale + xoffset,
                hpt1[1] * yscale + yoffset);
        fprintf(adjfile, "%f %f l\nk\n",
                hpt2[0] * xscale + xoffset,
                hpt2[1] * yscale + yoffset);
      }
    }
  }
  for (i = 0; i < subdomains; i++) {
    point1 = &center[i * 3];
    hpt1[0] = point1[0] - xcenter;
    hpt1[1] = point1[1] - ycenter;
    hpt1[2] = point1[2] - zcenter;
    mult_matvec(viewmatrix, hpt1, hpt1);
/*    perspectiveproj(hpt1, &pt1); */
    if (!bw_ps) {
      colorindex = i & 63;
      fprintf(adjfile, "%6.3f %6.3f %6.3f s\n",
              (showmereal) rgb[colorindex].red / 65535.0,
              (showmereal) rgb[colorindex].green / 65535.0,
              (showmereal) rgb[colorindex].blue / 65535.0);
      fprintf(adjfile, "%f %f %d 0 360 arc\nfill\n",
              hpt1[0] * xscale + xoffset, hpt1[1] * yscale + yoffset,
              5 + (line_width >> 1));
    } else {
      fprintf(adjfile, "%f %f %d 0 360 arc\nfill\n",
              hpt1[0] * xscale + xoffset, hpt1[1] * yscale + yoffset,
              3 + (line_width >> 1));
    }
  }
}

void print_data2d(FILE *datafile,
                  showmelong nodes,
                  showmelong elems,
                  showmelong datavalues,
                  showmereal *nodeptr,
                  showmelong *eleptr,
                  showmereal *dataptr,
                  showmereal *datahist,
                  showmereal xcenter,
                  showmereal ycenter,
                  showmereal xscale,
                  showmereal yscale,
                  showmereal xoffset,
                  showmereal yoffset,
                  int llcornerx,
                  int llcornery)
{
  showmelong i, j;
  int index;

  showmereal *point1, *point2, backz;
  vector_t hpt1, hpt2;
  showmereal normx, normy, normz, norm;
  int shade;

  showmereal datafac = 5.0 / (datahist[1] - datahist[0]);
  showmereal dataoffset = 0.5 * (datahist[0] + datahist[1]) * datafac;

  XPoint *final;

  struct facelist *drawfaces = (struct facelist *)
                               malloc(elems * sizeof(struct facelist));
  XPoint *vertices = (XPoint *) malloc(sizeof(XPoint) * elems * 3 + 4);
  struct vec_t corner[4];

  if (!bw_ps) {
    fprintf(datafile, "0 0 0 s\n");
    fprintf(datafile, "%d %d m\n", llcornerx, llcornery);
    fprintf(datafile, "%d %d l\n", 612 - llcornerx, llcornery);
    fprintf(datafile, "%d %d l\n", 612 - llcornerx, 792 - llcornery);
    fprintf(datafile, "%d %d l\n", llcornerx, 792 - llcornery);
    fprintf(datafile, "fill\n");
  }

  index = 3;
  for (i = 1; i <=elems * 3; i++) {
    if (eleptr[index] >= 0) {
      point1 = &nodeptr[eleptr[index] * 2];
      if (index % 3 == 0) {
        point2 = &nodeptr[eleptr[index + 2] * 2];
      } else {
        point2 = &nodeptr[eleptr[index - 1] * 2];
      }

      hpt1[0] = point1[0] - xcenter;
      hpt1[1] = point1[1] - ycenter;
      hpt1[2] = dataptr[eleptr[index] / 2 + 1] * datafac - dataoffset;
      mult_matvec(viewmatrix, hpt1, hpt1);
      backz = hpt1[2];
/*      perspectiveproj(hpt1, &pt1); */

      if (wireframe) {
        hpt2[0] = point2[0] - xcenter;
        hpt2[1] = point2[1] - ycenter;
        if (index % 3 == 0) {
          hpt2[2] = dataptr[eleptr[index + 2] / 2 + 1] * datafac - dataoffset;
        } else {
          hpt2[2] = dataptr[eleptr[index - 1] / 2 + 1] * datafac - dataoffset;
        }
        mult_matvec(viewmatrix, hpt2, hpt2);
/*        perspectiveproj(hpt2, &pt2); */
      }

      if (wireframe) {
        fprintf(datafile, "%f %f m\n",
                (hpt1[0] - xcenter) * xscale + xoffset,
                (hpt1[1] - ycenter) * yscale + yoffset);
        fprintf(datafile, "%f %f l\n",
                (hpt2[0] - xcenter) * xscale + xoffset,
                (hpt2[1] - ycenter) * yscale + yoffset);
      } else {
        vertices[i - 1].x = (int) ((hpt1[0] - xcenter) * xscale + xoffset);
        vertices[i - 1].y = (int) ((hpt1[1] - ycenter) * yscale + yoffset);

	j = (i - 1) / 3;

        if ((i - 1) % 3 == 0) {
          drawfaces[j].whichtet = i - 1;
          drawfaces[j].z = 0.0;
        }
        drawfaces[j].z += backz;

        corner[(i - 1) % 3].x = hpt1[0] * xscale + xoffset;
        corner[(i - 1) % 3].y = hpt1[1] * yscale + yoffset;
        corner[(i - 1) % 3].z = backz * 100.0;

        if ((i - 1) % 3 == 2) {
          normx = (corner[1].y - corner[0].y) * (corner[2].z - corner[0].z) -
                  (corner[1].z - corner[0].z) * (corner[2].y - corner[0].y);
          normy = (corner[1].z - corner[0].z) * (corner[2].x - corner[0].x) -
                  (corner[1].x - corner[0].x) * (corner[2].z - corner[0].z);
          normz = (corner[1].x - corner[0].x) * (corner[2].y - corner[0].y) -
                  (corner[1].y - corner[0].y) * (corner[2].x - corner[0].x);

          norm = normx * normx + normy * normy + normz * normz;
          if (norm == 0.0) {
            normx = 0.0;
            normy = 0.0;
            normz = 1.0;
            norm = 1.0;
          } else {
            norm = 1.0 / sqrt(norm);
          }
          if (normz < 0.0) {
            normx = - normx;
            normy = - normy;
            normz = - normz;
          }
          shade = (int) ((normx * lightsourcex +
                          normy * lightsourcey +
                          normz * lightsourcez) * norm * 65536.0);
          if (shade < 0) {
            shade = 0;
          } else if (shade >= 65536) {
            /* This should never happen. */
            shade = 65535;
          }
          drawfaces[j - 1].color = shade;
        }
      }
      index++;
    }
  }

  if (!wireframe) {
    if (elems > 1) {
      sortfaces(drawfaces, elems);
    }
    for (j = 0; j < elems; j++) {
      final = vertices + drawfaces[j].whichtet;

      fprintf(datafile, "%6.3f %6.3f %6.3f s\n",
              (showmereal) drawfaces[j].color / 65535.0,
              (showmereal) drawfaces[j].color / 65535.0,
              (showmereal) drawfaces[j].color / 65535.0);

      fprintf(datafile, "%d %d m\n", final[0].x, final[0].y);
      fprintf(datafile, "%d %d l\n", final[1].x, final[1].y);
      fprintf(datafile, "%d %d l\n", final[2].x, final[2].y);
      fprintf(datafile, "%d %d l\n", final[0].x, final[0].y);

      fprintf(datafile, "gsave\nclosepath\nclip\nfill\ngrestore\n");

      fprintf(datafile, "1 1 0 s\n");

      /* outline the solid polygons */
      fprintf(datafile, "%d %d m\n", final[0].x, final[0].y);
      fprintf(datafile, "%d %d l\n", final[1].x, final[1].y);
      fprintf(datafile, "%d %d l\n", final[2].x, final[2].y);
      fprintf(datafile, "%d %d l\n", final[0].x, final[0].y);
      fprintf(datafile, "gsave\ngrestore\nk\n");
    }
  }
  fprintf(datafile, "k\n");
}

void print_image(int inc,
                 int image,
                 showmereal xcenter,
                 showmereal ycenter,
                 showmereal zcenter,
                 showmereal xwidth,
                 showmereal ywidth,
                 showmereal xtrans,
                 showmereal ytrans,
                 int eps)
{
  FILE *psfile;
  showmereal xxscale, yyscale, xxoffset, yyoffset;
  char psfilename[FILENAMESIZE];
  int llcornerx, llcornery;

  if (image == NOTHING) {
    return;
  }
  if (!loaded[inc][image]) {
    return;
  }
  if ((image == PART) && (explode || bw_ps)) {
    xwidth *= (1.0 + explosion);
    ywidth *= (1.0 + explosion);
  }
  xxscale = (460.0 - (showmereal) line_width) / xwidth;
  yyscale = (640.0 - (showmereal) line_width) / ywidth;
  if (xxscale > yyscale) {
    xxscale = yyscale;
    llcornerx = (604 - (int) (yyscale * xwidth) - line_width) >> 1;
    llcornery = 72;
  } else {
    yyscale = xxscale;
    llcornerx = 72;
    llcornery = (784 - (int) (xxscale * ywidth) - line_width) >> 1;
  }
  xxoffset = 306.0 + xtrans * xxscale;
  yyoffset = 396.0 + ytrans * yyscale;
  switch(image) {
    case NODE:
      addps(nodefilename[inc], psfilename, eps);
      break;
    case POLY:
      addps(polyfilename[inc], psfilename, eps);
      break;
    case ELE:
      addps(elefilename[inc], psfilename, eps);
      break;
    case EDGE:
      addps(edgefilename[inc], psfilename, eps);
      break;
    case PART:
      addps(partfilename[inc], psfilename, eps);
      break;
    case ADJ:
      addps(adjfilename[inc], psfilename, eps);
      break;
    case VORO:
      addps(vedgefilename[inc], psfilename, eps);
      break;
    case DATA:
      addps(datafilename[inc], psfilename, eps);
      break;
    default:
      break;
  }
  if (print_head(psfilename, &psfile, llcornerx, llcornery, eps)) {
    return;
  }
  switch(image) {
    case NODE:
      if (nodedim[inc] == 2) {
        print_node2d(psfile, nodes[inc], nodeptr[inc], xcenter, ycenter,
                     xxscale, yyscale, xxoffset, yyoffset);
      } else {
        print_node3d(psfile, nodes[inc], nodeptr[inc],
                     xcenter, ycenter, zcenter, xxscale, yyscale,
                     xxoffset, yyoffset);
      }
      break;
    case POLY:
      if (polynodes[inc] > 0) {
        if (polydim[inc] == 2) {
          print_poly2d(psfile, polynodes[inc], polyedges[inc],
                       polynodeptr[inc], polysegptr[inc], xcenter, ycenter,
                       xxscale, yyscale, xxoffset, yyoffset);
        }
      } else {
        if (nodedim[inc] == 2) {
          print_poly2d(psfile, nodes[inc], polyedges[inc], nodeptr[inc],
                       polysegptr[inc], xcenter, ycenter,  xxscale, yyscale,
                       xxoffset, yyoffset);
        }
      }
      break;
    case ELE:
      if (nodedim[inc] == 2) {
        print_ele2d(psfile, elems[inc], nodeptr[inc], eleptr[inc],
                    (int *) NULL, (showmereal *) NULL, xcenter, ycenter,
                    xxscale, yyscale, xxoffset, yyoffset,
                    llcornerx, llcornery);
      } else {
        print_ele3d(psfile, elems[inc], nodeptr[inc], eleptr[inc],
                    (int *) NULL, (showmereal *) NULL,
                    xcenter, ycenter, zcenter,
                    xxscale, yyscale, xxoffset, yyoffset,
                    llcornerx, llcornery);
      }
      break;
    case EDGE:
      if (nodedim[inc] == 2) {
        print_edge2d(psfile, nodes[inc], edges[inc], nodeptr[inc],
                     edgeptr[inc], normptr[inc], xcenter, ycenter,
                     xxscale, yyscale, xxoffset, yyoffset,
                     llcornerx, llcornery);
      } else {
        print_edge3d(psfile, nodes[inc], edges[inc], nodeptr[inc],
                     edgeptr[inc], xcenter, ycenter, zcenter,
                     xxscale, yyscale, xxoffset, yyoffset,
                     llcornerx, llcornery);
      }
      break;
    case PART:
      if (nodedim[inc] == 2) {
        print_ele2d(psfile, elems[inc], nodeptr[inc], eleptr[inc],
                    partition[inc], subdomshift[inc], xcenter, ycenter,
                    xxscale, yyscale, xxoffset, yyoffset,
                    llcornerx, llcornery);
      } else {
        print_ele3d(psfile, elems[inc], nodeptr[inc], eleptr[inc],
                    partition[inc], subdomshift[inc],
                    xcenter, ycenter, zcenter,
                    xxscale, yyscale, xxoffset, yyoffset,
                    llcornerx, llcornery);
      }
      break;
    case ADJ:
      if (nodedim[inc] == 2) {
        print_adj2d(psfile, adjsubdomains[inc], adjptr[inc], subdomcenter[inc],
                    xcenter, ycenter, xxscale, yyscale, xxoffset, yyoffset,
                    llcornerx, llcornery);
      } else {
        print_adj3d(psfile, adjsubdomains[inc], adjptr[inc], subdomcenter[inc],
                    xcenter, ycenter, zcenter, xxscale, yyscale,
                    xxoffset, yyoffset, llcornerx, llcornery);
      }
      break;
    case VORO:
      if (vnodedim[inc] == 2) {
        if (loaded[inc][NODE]) {
          if (nodedim[inc] == 2) {
            print_node2d(psfile, nodes[inc], nodeptr[inc], xcenter, ycenter,
                         xxscale, yyscale, xxoffset, yyoffset);
          }
        }
        print_edge2d(psfile, vnodes[inc], vedges[inc], vnodeptr[inc],
                     vedgeptr[inc], vnormptr[inc], xcenter, ycenter,
                     xxscale, yyscale, xxoffset, yyoffset,
                     llcornerx, llcornery);
      }
      break;
    case DATA:
      if (nodedim[inc] == 2) {
        print_data2d(psfile, nodes[inc], elems[inc], datavalues[inc],
                     nodeptr[inc], eleptr[inc], dataptr[inc], datahist[inc],
                     xcenter, ycenter, xxscale, yyscale, xxoffset, yyoffset,
                     llcornerx, llcornery);
      }
      break;
    default:
      break;
  }
  if (!eps) {
    fprintf(psfile, "showpage\n");
  }
  fclose(psfile);
}

/*
 *  The next section allows the user to slice away a portion of a 3D mesh.
 *  The mechanism is to project the mesh points to the screen and set a flag
 *  to 0 (no plotting) to all those tetrahedra whose projected centers are
 *  to the left, right, above, or below, depending on the cut.
 *
 *  Also, those tetrahedra that are internal (have all 4 faces shared with
 *  other tetrahedra) and are on the cutting plane will be plotted.  Multiple
 *  cuts are also possible with trim_tetrahedron, as previously cutout tetra
 *  will not be displayed.
 */

void trim_tetrahedra(int trim_direction,
                     showmelong elems,
                     showmereal *nodeptr,
                     showmelong *eleptr)
{
  showmelong i;
  int j;
  vector_t hpt;
  showmereal xptr, yptr;
  showmelong firsttet;
  int adjacent;

  do {
    XNextEvent(display, &event);
  } while (event.type != ButtonRelease);
  xptr = ((showmereal) event.xbutton.x - xoffset) / xscale;
  yptr = ((showmereal) event.xbutton.y - yoffset) / yscale;
  draw_buttons();

  for (i = 1; i <= elems; i++) {
    if (!tetraptr[i].invisible) {
      hpt[0] = 0.0;
      hpt[1] = 0.0;
      hpt[2] = 0.0;
      for (j = 0; j < 4; j++) {
        hpt[0] += nodeptr[eleptr[i * 4 + j] * 3];
        hpt[1] += nodeptr[eleptr[i * 4 + j] * 3 + 1];
        hpt[2] += nodeptr[eleptr[i * 4 + j] * 3 + 2];
      }
      hpt[0] = 0.25 * hpt[0] - xcenter;
      hpt[1] = 0.25 * hpt[1] - ycenter;
      hpt[2] = 0.25 * hpt[2] - zcenter;
      mult_matvec(viewmatrix, hpt, hpt);
/*      perspectiveproj(hpt, &centroid); */

      if (((trim_direction == TRIMLEFT) && (hpt[0] < xptr)) ||
          ((trim_direction == TRIMRIGHT) && (hpt[0] > xptr)) ||
          ((trim_direction == TRIMDOWN) && (hpt[1] < yptr)) ||
          ((trim_direction == TRIMUP) && (hpt[1] > yptr))) {
        tetraptr[i].invisible = 1;
        for (j = 0; j < 4; j++) {
          adjacent = tetraptr[i].neighbor[j];
          if (adjacent != 0) {
            if (adjacent < 0) {
              adjacent = -adjacent;
            }
            tetraptr[adjacent >> 2].neighbor[adjacent & 3] =
                    -tetraptr[adjacent >> 2].neighbor[adjacent & 3];
          }
        }
      }
    }
  }

  firsttet = 0;
  for (i = elems; i > 0; i--) {
    if (!tetraptr[i].invisible) {
      if ((tetraptr[i].neighbor[0] <= 0)
          || (tetraptr[i].neighbor[1] <= 0)
          || (tetraptr[i].neighbor[2] <= 0)
          || (tetraptr[i].neighbor[3] <= 0)) {
        tetraptr[i].nexttet = firsttet;
        firsttet = i;
      }
    }
  }
  tetraptr[0].nexttet = firsttet;
}

void quality_tetrahedra(showmereal quality,
                        showmereal *nodeptr,
                        showmelong *eleptr,
                        showmelong elems,
                        int dim)
{
  showmereal p[4][3];
  showmereal quality2;
  showmereal dx[3][4], dy[3][4], dz[3][4];
  showmereal edgelength[3][4];
  showmereal ji[3], ki[3];
  showmereal kcrossj[3];
  showmereal pyrvolume;
  showmereal facearea2;
  showmereal biggestface;
  showmereal pyrlongest2;
  showmereal pyrminaltitude2;
  showmereal pyraspect2;
  showmelong thiselem;
  int pointindex;
  showmelong firsttet;
  int adjacent;
  int i, j, k;

  quality2 = quality * quality;
  for (thiselem = 1; thiselem <= elems; thiselem++) {
    if (!tetraptr[thiselem].invisible) {
      for (j = 0; j < 4; j++) {
        pointindex = 3 * eleptr[thiselem * 4 + j];
        p[j][0] = nodeptr[pointindex];
        p[j][1] = nodeptr[pointindex + 1];
        p[j][2] = nodeptr[pointindex + 2];
      }
      pyrlongest2 = 0.0;
      biggestface = 0.0;
      for (i = 0; i < 3; i++) {
        j = (i + 1) & 3;
        k = (i + 2) & 3;
        ji[0] = p[j][0] - p[i][0];
        ji[1] = p[j][1] - p[i][1];
        ji[2] = p[j][2] - p[i][2];
        ki[0] = p[k][0] - p[i][0];
        ki[1] = p[k][1] - p[i][1];
        ki[2] = p[k][2] - p[i][2];
        kcrossj[0] = ki[1] * ji[2] - ki[2] * ji[1];
        kcrossj[1] = ki[2] * ji[0] - ki[0] * ji[2];
        kcrossj[2] = ki[0] * ji[1] - ki[1] * ji[0];
        facearea2 = kcrossj[0] * kcrossj[0] + kcrossj[1] * kcrossj[1]
                  + kcrossj[2] * kcrossj[2];
        if (facearea2 > biggestface) {
          biggestface = facearea2;
        }
        for (j = i + 1; j < 4; j++) {
          dx[i][j] = p[i][0] - p[j][0];
          dy[i][j] = p[i][1] - p[j][1];
          dz[i][j] = p[i][2] - p[j][2];
          edgelength[i][j] = dx[i][j] * dx[i][j] + dy[i][j] * dy[i][j]
                           + dz[i][j] * dz[i][j];
          if (edgelength[i][j] > pyrlongest2) {
            pyrlongest2 = edgelength[i][j];
          }
        }
      }
      pyrvolume = orient3d(p[0], p[1], p[2], p[3]);
      pyrminaltitude2 = pyrvolume * pyrvolume / biggestface;
      pyraspect2 = pyrlongest2 / pyrminaltitude2;

      if (pyraspect2 < quality2) {
        tetraptr[thiselem].invisible = 1;
        for (j = 0; j < 4; j++) {
          adjacent = tetraptr[thiselem].neighbor[j];
          if (adjacent != 0) {
            if (adjacent < 0) {
              adjacent = -adjacent;
            }
            tetraptr[adjacent >> 2].neighbor[adjacent & 3] =
                    -tetraptr[adjacent >> 2].neighbor[adjacent & 3];
          }
        }
      }
    }
  }

  firsttet = 0;
  for (i = elems; i > 0; i--) {
    if (!tetraptr[i].invisible) {
      if ((tetraptr[i].neighbor[0] <= 0)
          || (tetraptr[i].neighbor[1] <= 0)
          || (tetraptr[i].neighbor[2] <= 0)
          || (tetraptr[i].neighbor[3] <= 0)) {
        tetraptr[i].nexttet = firsttet;
        firsttet = i;
      }
    }
  }
  tetraptr[0].nexttet = firsttet;
}

int main(int argc,
         char **argv)
{
  showmereal xwidth, ywidth, zwidth;
  showmereal xtrans, ytrans;
  showmereal xptr, yptr;
  showmereal quality;
  showmereal AmtTilt = 15.0;
  matrix_t matrix;
  int past_image;
  int new_image;
  int new_inc;
  int lastPan = 0, lastTilt = 0, Pan, Tilt;
  showmelong firsttet;
  int adjacent;
  int addtolist;
  int done;
  int i, j;
  char *instring;

  parsecommandline(argc, argv);
  showme_init();
  choose_image(start_inc, start_image);

  showme_window(argc, argv);

  if (current_image != NOTHING) {
    xcenter = 0.5 * (xlo[current_inc][current_image]
                     + xhi[current_inc][current_image]);
    ycenter = 0.5 * (ylo[current_inc][current_image]
                     + yhi[current_inc][current_image]);
    zcenter = 0.5 * (zlo[current_inc][current_image]
                     + zhi[current_inc][current_image]);
    xwidth = xhi[current_inc][current_image] - xlo[current_inc][current_image];
    ywidth = yhi[current_inc][current_image] - ylo[current_inc][current_image];
    if (nodedim[current_inc] == 3) {
      zwidth = zhi[current_inc][current_image]
             - zlo[current_inc][current_image];
      if ((zwidth > xwidth) && (zwidth > ywidth)) {
        xwidth = ywidth = 1.3 * zwidth;
      } else if (ywidth > xwidth) {
        xwidth = ywidth = 1.3 * ywidth;
      } else {
        xwidth = ywidth = 1.3 * xwidth;
      }
    }
    zoom = 0;
    xtrans = 0;
    ytrans = 0;
  }

  XMaskEvent(display, ExposureMask, &event);
  while (1) {
    switch (event.type) {
      case MotionNotify:
        if (motion &&
            ((current_image == DATA) || (nodedim[current_inc] == 3))) {
          Pan = (showmereal) (event.xbutton.x - lastPan) * 0.1 * AmtTilt;
          Tilt = (showmereal) (event.xbutton.y - lastTilt) * 0.1 * AmtTilt;
	  lastPan = event.xbutton.x;
	  lastTilt = event.xbutton.y;

	  three_D_rot_matrix_y(matrix, Pan * DEG2RAD);
	  mult_matmat(matrix, viewmatrix, viewmatrix);
	  three_D_rot_matrix_x(matrix, Tilt * DEG2RAD);
	  mult_matmat(matrix, viewmatrix, viewmatrix);

          draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                     xwidth, ywidth, xtrans, ytrans);
          while (XCheckMaskEvent(display, PointerMotionMask, &event));
        }
        break;
      case ButtonRelease:
        if (event.xany.window == quitwin) {
          XDestroyWindow(display, mainwindow);
          XCloseDisplay(display);
          return 0;
        } else if (event.xany.window == leftwin) {
          xtrans -= 0.125 * xwidth;
	  amtLeft += 0.125;
          draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                     xwidth, ywidth, xtrans, ytrans);
        } else if (event.xany.window == rightwin) {
          xtrans += 0.125 * xwidth;
	  amtLeft -= 0.125;
          draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                     xwidth, ywidth, xtrans, ytrans);
        } else if (event.xany.window == upwin) {
          ytrans += 0.125 * xwidth;
	  amtUp += 0.125;
          draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                     xwidth, ywidth, xtrans, ytrans);
        } else if (event.xany.window == downwin) {
          ytrans -= 0.125 * xwidth;
	  amtUp -= 0.125;
          draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                     xwidth, ywidth, xtrans, ytrans);
        } else if (event.xany.window == resetwin) {
          done = 0;
          if ((nodedim[current_inc] == 3) &&
              ((current_image == ELE) || (current_image == PART)
               || (current_image == DATA))) {
            firsttet = 0;
	    for (i = elems[current_inc]; i > 0; i--) {
	      if (tetraptr[i].invisible) {
                tetraptr[i].invisible = 0;
                done = 1;
              }
              addtolist = 0;
              for (j = 0; j < 4; j++) {
                adjacent = tetraptr[i].neighbor[j];
                if (adjacent < 0) {
                  tetraptr[i].neighbor[j] = -adjacent;
                } else if (adjacent == 0) {
                  addtolist = 1;
                }
              }
              if (addtolist) {
                tetraptr[i].nexttet = firsttet;
                firsttet = i;
              }
	    }
            tetraptr[0].nexttet = firsttet;
	  }

          if (!done) {
            xcenter = 0.5 * (xlo[current_inc][current_image]
                             + xhi[current_inc][current_image]);
            ycenter = 0.5 * (ylo[current_inc][current_image]
                             + yhi[current_inc][current_image]);
            zcenter = 0.5 * (zlo[current_inc][current_image]
                             + zhi[current_inc][current_image]);
            xwidth = xhi[current_inc][current_image]
                   - xlo[current_inc][current_image];
            ywidth = yhi[current_inc][current_image]
                   - ylo[current_inc][current_image];
            if (nodedim[current_inc] == 3) {
              zwidth = zhi[current_inc][current_image]
                    - zlo[current_inc][current_image];
              if ((zwidth > xwidth) && (zwidth > ywidth)) {
                xwidth = 1.3 * zwidth;
                ywidth = 1.3 * zwidth;
              } else if (ywidth > xwidth) {
                xwidth = 1.3 * ywidth;
              } else {
                ywidth = 1.3 * xwidth;
              }
            }

            if ((zoom == 0) && (xtrans == 0) && (ytrans == 0)) {
              identitymatrix(viewmatrix);
              perspfactor = 1.5;
            }
            zoom = 0;
            xtrans = 0;
            ytrans = 0;
          }

          draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                     xwidth, ywidth, xtrans, ytrans);
        } else if (event.xany.window == widthpluswin) {
          if (line_width < 100) {
            line_width++;
            XSetLineAttributes(display, linegc, line_width, LineSolid,
                               CapRound, JoinRound);
            XSetLineAttributes(display, trianglegc, line_width, LineSolid,
                               CapRound, JoinRound);
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
        } else if (event.xany.window == widthminuswin) {
          if (line_width > 1) {
            line_width--;
            XSetLineAttributes(display, linegc, line_width, LineSolid,
                               CapRound, JoinRound);
            XSetLineAttributes(display, trianglegc, line_width, LineSolid,
                               CapRound, JoinRound);
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
        } else if (event.xany.window == expwin) {
          if ((current_image == PART) && loaded[current_inc][PART]) {
            explode = !explode;
	    dlist_drawn = 0;
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
        } else if (event.xany.window == exppluswin) {
          if ((current_image == PART) && loaded[PART] && explode) {
            explosion += 0.125;
	    dlist_drawn = 0;
            findsubdomshift(nodedim[current_inc], subdomains[current_inc],
                            explosion, subdomcenter[current_inc],
                            subdomshift[current_inc]);
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
        } else if (event.xany.window == expminuswin) {
          if ((current_image == PART) && loaded[PART] && explode &&
              (explosion >= 0.125)) {
            explosion -= 0.125;
            findsubdomshift(nodedim[current_inc], subdomains[current_inc],
                            explosion, subdomcenter[current_inc],
                            subdomshift[current_inc]);
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
        } else if (event.xany.window == fillwin) {
          if (((current_image == PART) && loaded[PART]) ||
              ((current_image == DATA) && loaded[DATA])) {
            fillelem = !fillelem;
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
        } else if (event.xany.window == pswin) {
          fill_button(pswin);
          XDrawString(display, pswin, blackfontgc, 2, 13, "PS", 2);
          XFlush(display);
          print_image(current_inc, current_image, xcenter, ycenter, zcenter,
                      xwidth, ywidth, xtrans, ytrans, 0);
          XClearWindow(display, pswin);
          XDrawString(display, pswin, fontgc, 2, 13, "PS", 2);
        } else if (event.xany.window == epswin) {
          fill_button(epswin);
          XDrawString(display, epswin, blackfontgc, 2, 13, "EPS", 3);
          XFlush(display);
          print_image(current_inc, current_image, xcenter, ycenter, zcenter,
                      xwidth, ywidth, xtrans, ytrans, 1);
          XClearWindow(display, epswin);
          XDrawString(display, epswin, fontgc, 2, 13, "EPS", 3);
        } else if (event.xany.window == versionpluswin) {
          move_inc(1);
          loweriteration++;
          setfilenames(filename, loweriteration);
          if (current_inc == 1) {
            current_inc = 0;
          } else {
            current_image = NOTHING;
            XClearWindow(display, mainwindow);
          }
        } else if (event.xany.window == versionminuswin) {
          if (loweriteration > 0) {
            move_inc(0);
            loweriteration--;
            setfilenames(filename, loweriteration);
            if (current_inc == 0) {
              current_inc = 1;
            } else {
              current_image = NOTHING;
              XClearWindow(display, mainwindow);
            }
          }
        } else if (event.xany.window == motionwin) {
          if ((current_image == DATA) || (nodedim[current_inc] == 3)) {
            motion = !motion;
            if (motion) {
              printf("Press middle button to turn off rotation.\n");
              lastPan = event.xbutton.x;
              lastTilt = event.xbutton.y;
            }
          }
	} else if (event.xany.window == rotateamtwin) {
          if ((current_image == DATA) || (nodedim[current_inc] == 3)) {
            instring = get_line("Rotation (degrees):");
            AmtTilt = atof(instring);
          }
	} else if ((event.xany.window == rotatewin[0])
                   || (event.xany.window == rotatewin[1])) {
	  if (event.xany.window == rotatewin[0]) {
            Tilt = AmtTilt;
          } else {
            Tilt = -AmtTilt;
          }
	  three_D_rot_matrix_x(matrix, Tilt * DEG2RAD);
	  mult_matmat(matrix, viewmatrix, viewmatrix);
          draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                     xwidth, ywidth, xtrans, ytrans);
        } else if ((event.xany.window == rotatewin[2])
                   || (event.xany.window == rotatewin[3])) {
	  if (event.xany.window == rotatewin[2]) {
            Pan = -AmtTilt;
          } else {
            Pan = AmtTilt;
          }
	  three_D_rot_matrix_y(matrix, Pan * DEG2RAD);
	  mult_matmat(matrix, viewmatrix, viewmatrix);
          draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                     xwidth, ywidth, xtrans, ytrans);
        } else if ((event.xany.window == rotatewin[4])
                   || (event.xany.window == rotatewin[5])) {
	  if (event.xany.window == rotatewin[4]) {
            Camera_Twist = AmtTilt;
          } else {
            Camera_Twist = -AmtTilt;
          }
	  three_D_rot_matrix_z(matrix, Camera_Twist * DEG2RAD);
	  mult_matmat(matrix, viewmatrix, viewmatrix);
          draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                     xwidth, ywidth, xtrans, ytrans);
        } else if (event.xany.window == wireframeoptionwin) {
          if ((current_image == DATA) || (nodedim[current_inc] == 3)) {
            wireframe = !wireframe;
            dlist_drawn = 0;
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
        } else if (event.xany.window == perspectivewin) {
          if ((current_image == DATA) || (nodedim[current_inc] == 3)) {
            perspective = !perspective;
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
        } else if (event.xany.window == perspluswin) {
          if (perspective
              && ((current_image == DATA) || (nodedim[current_inc] == 3))) {
	    perspfactor *= 0.8;
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
	  }
        } else if (event.xany.window == persminuswin) {
	  if (perspective
              && (current_image == DATA || nodedim[current_inc] == 3)) {
	    perspfactor *= 1.25;
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
	  }
	} else if (event.xany.window == cutleftwin) {
          if ((nodedim[current_inc] == 3) &&
              ((current_image == ELE) || (current_image == PART)
               || (current_image == DATA))) {
            fill_button(cutleftwin);
            XDrawString(display, cutleftwin, blackfontgc, 2, 13, "Cut<", 4);
            trim_tetrahedra(TRIMLEFT, elems[current_inc], nodeptr[current_inc],
                            eleptr[current_inc]);
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
	} else if (event.xany.window == cutrightwin) {
          if ((nodedim[current_inc] == 3) &&
              ((current_image == ELE) || (current_image == PART)
               || (current_image == DATA))) {
            fill_button(cutrightwin);
            XDrawString(display, cutrightwin, blackfontgc, 2, 13, ">", 1);
            trim_tetrahedra(TRIMRIGHT, elems[current_inc],
                            nodeptr[current_inc], eleptr[current_inc]);
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
	} else if (event.xany.window == cutupwin) {
          if ((nodedim[current_inc] == 3) &&
              ((current_image == ELE) || (current_image == PART)
               || (current_image == DATA))) {
            fill_button(cutupwin);
            XDrawString(display, cutupwin, blackfontgc, 2, 13, "^", 1);
            trim_tetrahedra(TRIMUP, elems[current_inc], nodeptr[current_inc],
                            eleptr[current_inc]);
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
	} else if (event.xany.window == cutdownwin) {
          if ((nodedim[current_inc] == 3) &&
              ((current_image == ELE) || (current_image == PART)
               || (current_image == DATA))) {
            fill_button(cutdownwin);
            XDrawString(display, cutdownwin, blackfontgc, 2, 13, "v", 1);
            trim_tetrahedra(TRIMDOWN, elems[current_inc], nodeptr[current_inc],
                            eleptr[current_inc]);
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
	} else if (event.xany.window == qualitywin) {
          if ((nodedim[current_inc] == 3) &&
              ((current_image == ELE) || (current_image == PART)
               || (current_image == DATA))) {
            instring = get_line("Aspect ratio:");
            quality = atof(instring);
            quality_tetrahedra(quality, nodeptr[current_inc],
                               eleptr[current_inc], elems[current_inc],
                               nodedim[current_inc]);
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          }
	} else if ((event.xany.window == nodewin[0]) ||
                   (event.xany.window == polywin[0]) ||
                   (event.xany.window == elewin[0]) ||
                   (event.xany.window == edgewin[0]) ||
                   (event.xany.window == partwin[0]) ||
                   (event.xany.window == adjwin[0]) ||
                   (event.xany.window == voronoiwin[0]) ||
                   (event.xany.window == datawin[0]) ||
                   (event.xany.window == nodewin[1]) ||
                   (event.xany.window == polywin[1]) ||
                   (event.xany.window == elewin[1]) ||
                   (event.xany.window == edgewin[1]) ||
                   (event.xany.window == partwin[1]) ||
                   (event.xany.window == adjwin[1]) ||
                   (event.xany.window == voronoiwin[1]) ||
                   (event.xany.window == datawin[1])) {
          if (event.xany.window == nodewin[0]) {
            new_inc = 0;
            new_image = NODE;
          }
          if (event.xany.window == polywin[0]) {
            new_inc = 0;
            new_image = POLY;
          }
          if (event.xany.window == elewin[0]) {
            new_inc = 0;
            new_image = ELE;
          }
          if (event.xany.window == edgewin[0]) {
            new_inc = 0;
            new_image = EDGE;
          }
          if (event.xany.window == partwin[0]) {
            new_inc = 0;
            new_image = PART;
          }
          if (event.xany.window == adjwin[0]) {
            new_inc = 0;
            new_image = ADJ;
          }
          if (event.xany.window == voronoiwin[0]) {
            new_inc = 0;
            new_image = VORO;
          }
          if (event.xany.window == datawin[0]) {
            new_inc = 0;
            new_image = DATA;
          }
          if (event.xany.window == nodewin[1]) {
            new_inc = 1;
            new_image = NODE;
          }
          if (event.xany.window == polywin[1]) {
            new_inc = 1;
            new_image = POLY;
          }
          if (event.xany.window == elewin[1]) {
            new_inc = 1;
            new_image = ELE;
          }
          if (event.xany.window == edgewin[1]) {
            new_inc = 1;
            new_image = EDGE;
          }
          if (event.xany.window == partwin[1]) {
            new_inc = 1;
            new_image = PART;
          }
          if (event.xany.window == adjwin[1]) {
            new_inc = 1;
            new_image = ADJ;
          }
          if (event.xany.window == voronoiwin[1]) {
            new_inc = 1;
            new_image = VORO;
          }
          if (event.xany.window == datawin[1]) {
            new_inc = 1;
            new_image = DATA;
          }
          past_image = current_image;
          if ((current_inc == new_inc) && (current_image == new_image)) {
            free_inc(new_inc);
            unload_inc(new_inc);
          }
          choose_image(new_inc, new_image);
          if ((past_image == NOTHING) && (current_image != NOTHING)) {
            xcenter = 0.5 * (xlo[current_inc][current_image]
                             + xhi[current_inc][current_image]);
            ycenter = 0.5 * (ylo[current_inc][current_image]
                             + yhi[current_inc][current_image]);
            zcenter = 0.5 * (zlo[current_inc][current_image]
                             + zhi[current_inc][current_image]);
            xwidth = xhi[current_inc][current_image]
                   - xlo[current_inc][current_image];
            ywidth = yhi[current_inc][current_image]
                   - ylo[current_inc][current_image];
            if (nodedim[current_inc] == 3) {
              zwidth = zhi[current_inc][current_image]
                     - zlo[current_inc][current_image];
              if ((zwidth > xwidth) && (zwidth > ywidth)) {
                xwidth = 1.3 * zwidth;
                ywidth = 1.3 * zwidth;
              } else if (ywidth > xwidth) {
                xwidth = 1.3 * ywidth;
              } else {
                ywidth = 1.3 * xwidth;
              }
            }
            zoom = 0;
            xtrans = 0;
            ytrans = 0;
          }
          draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                     xwidth, ywidth, xtrans, ytrans);
        } else {
	    xptr = ((showmereal) event.xbutton.x - xoffset) / xscale;
	    yptr = ((showmereal) event.xbutton.y - yoffset) / yscale;

          if ((current_image == PART) && loaded[PART] && explode) {
            xptr = (xptr + subdomcenter[current_inc]
                                       [subdomains[current_inc] *
                                        nodedim[current_inc]] *
                    explosion) / (1.0 + explosion);
            yptr = (yptr + subdomcenter[current_inc]
                                       [subdomains[current_inc] *
                                        nodedim[current_inc] + 1] *
                    explosion) / (1.0 + explosion);
          }
          if ((event.xbutton.button == Button1)
              || (event.xbutton.button == Button3)) {
            xtrans = -xptr;
            ytrans = -yptr;
            if (event.xbutton.button == Button1) {
              xwidth /= 1.1;
              ywidth /= 1.1;
              zoom++;
            } else {
              xwidth *= 1.1;
              ywidth *= 1.1;
              zoom--;
            }
            draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                       xwidth, ywidth, xtrans, ytrans);
          } else if (event.xbutton.button == Button2) {
            if ((nodedim[current_inc] == 3) || (current_image == DATA)) {
              motion = 0;
            } else {
              printf("x = %.4g, y = %.4g\n", xptr + xcenter, yptr + ycenter);
            }
          }
        }
        draw_buttons();
        break;
      case DestroyNotify:
        XDestroyWindow(display, mainwindow);
        XCloseDisplay(display);
        return 0;
      case ConfigureNotify:
        if ((width != event.xconfigure.width) ||
            (height != event.xconfigure.height - PANELHEIGHT)) {
          width = event.xconfigure.width;
          height = event.xconfigure.height - PANELHEIGHT;
          draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                     xwidth, ywidth, xtrans, ytrans);
          while (XCheckMaskEvent(display, ExposureMask, &event));
        }
        draw_buttons();
        break;
      case Expose:
        draw_image(current_inc, current_image, xcenter, ycenter, zcenter,
                   xwidth, ywidth, xtrans, ytrans);
        draw_buttons();
        while (XCheckMaskEvent(display, ExposureMask, &event));
        break;
      default:
        break;
    }
    XNextEvent(display, &event);
  }
}


<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkEmptyStencil.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkEmptyStencil.cxx,v $
  Language:  C++
  Date:      $Date: 2005/11/15 17:39:25 $
  Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkEmptyStencil.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkEmptyStencil);

void vtkvmtkEmptyStencil::Build()
  {
  if (this->PointIds && !this->ReallocateOnBuild)
    {
    return;
    }
  
  this->NPoints = 0;

  if (this->PointIds!=NULL)
    {
    delete[] this->PointIds;
    this->PointIds = NULL;
    }
  if (this->Weights!=NULL)
    {
    delete[] this->Weights;
    this->Weights = NULL;
    }
  if (this->CenterWeight!=NULL)
    {
    delete[] this->CenterWeight;
    this->CenterWeight = NULL;
    }
  }




<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkOpenNLLinearSystemSolver.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkOpenNLLinearSystemSolver.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:43 $
  Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkOpenNLLinearSystemSolver - Solve a linear system of equations using open NL.
// .SECTION Description
// There are a number of different solver types that can be used:
//    - VTK_VMTK_OPENNL_SOLVER_BICGSTAB = Biconjugate gradient stabilized method
//    - VTK_VMTK_OPENNL_SOLVER_GMRES = Generalized minimal residual method
//    - VTK_VMTK_OPENNL_SOLVER_CG = Iterative conjugate gradient solver

#ifndef __vtkvmtkOpenNLLinearSystemSolver_h
#define __vtkvmtkOpenNLLinearSystemSolver_h

#include "vtkObject.h"
#include "vtkvmtkLinearSystemSolver.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkOpenNLLinearSystemSolver : public vtkvmtkLinearSystemSolver
{
public:
  static vtkvmtkOpenNLLinearSystemSolver* New();
  vtkTypeMacro(vtkvmtkOpenNLLinearSystemSolver,vtkvmtkLinearSystemSolver);

  int Solve() override;

  vtkSetMacro(SolverType,int);
  vtkGetMacro(SolverType,int);
  void SetSolverTypeToCG()
    { this->SetSolverType(VTK_VMTK_OPENNL_SOLVER_CG); }
  void SetSolverTypeToGMRES()
    { this->SetSolverType(VTK_VMTK_OPENNL_SOLVER_GMRES); }
  void SetSolverTypeToBiCGStab()
    { this->SetSolverType(VTK_VMTK_OPENNL_SOLVER_BICGSTAB); }

  vtkSetMacro(PreconditionerType,int);
  vtkGetMacro(PreconditionerType,int);
  void SetPreconditionerTypeToNone()
    { this->SetPreconditionerType(VTK_VMTK_OPENNL_PRECONDITIONER_NONE); }
  void SetPreconditionerTypeToJacobi()
    { this->SetPreconditionerType(VTK_VMTK_OPENNL_PRECONDITIONER_JACOBI); }
  void SetPreconditionerTypeToSSOR()
    { this->SetPreconditionerType(VTK_VMTK_OPENNL_PRECONDITIONER_SSOR); }

  vtkSetMacro(Omega,double);
  vtkGetMacro(Omega,double);

  //BTX
  enum
    {
      VTK_VMTK_OPENNL_SOLVER_CG,
      VTK_VMTK_OPENNL_SOLVER_GMRES,
      VTK_VMTK_OPENNL_SOLVER_BICGSTAB
    };
  //ETX
  
  //BTX
  enum
    {
      VTK_VMTK_OPENNL_PRECONDITIONER_NONE,
      VTK_VMTK_OPENNL_PRECONDITIONER_JACOBI,
      VTK_VMTK_OPENNL_PRECONDITIONER_SSOR
    };
  //ETX

protected:
  vtkvmtkOpenNLLinearSystemSolver();
  ~vtkvmtkOpenNLLinearSystemSolver() {};

  int SolverType;
  int PreconditionerType;
  double Omega;

private:
  vtkvmtkOpenNLLinearSystemSolver(const vtkvmtkOpenNLLinearSystemSolver&);  // Not implemented.
  void operator=(const vtkvmtkOpenNLLinearSystemSolver&);  // Not implemented.
};

#endif



<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineSphereDistance.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkCenterlineSphereDistance.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:46:43 $
Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkCenterlineSphereDistance - Collection of functions which compute point ids which are n-spheres away from a reference point.
// .SECTION Description
// Allows us to find points which are n-touching spheres upstream or downstream from a reference point. In this description, "touching sphere" refers to the the points on the centerline (one upstream, one downstream) which lie closest to ("touch") the surface of a sphere whose barycenter is located at the reference points location. In practice, this means that we use the centerline's MaximumInscribedSphereRadius point data as the "sphere" radius/surface. 
//
// This metric is used because it is a well behaved way to normalize the comparison of distance as vessel radius scales. 

#ifndef __vtkvmtkCenterlineSphereDistance_h
#define __vtkvmtkCenterlineSphereDistance_h

#include "vtkObject.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"

class vtkPolyData;
  
class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineSphereDistance : public vtkObject
{
  public: 
  vtkTypeMacro(vtkvmtkCenterlineSphereDistance,vtkObject);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 
  static vtkvmtkCenterlineSphereDistance* New();

  static void FindTouchingSphereCenter(vtkPolyData* centerlines, const char* radiusArrayName, vtkIdType cellId, vtkIdType subId, double pcoord, vtkIdType& touchingSubId, double& touchingPCoord, bool forward=true);

  static void FindNTouchingSphereCenter(vtkPolyData* centerlines, const char* radiusArrayName, vtkIdType cellId, vtkIdType subId, double pcoord, int numberOfTouchingSpheres, vtkIdType& touchingSubId, double& touchingPCoord, bool forward=true);

  protected:
  vtkvmtkCenterlineSphereDistance() {};
  ~vtkvmtkCenterlineSphereDistance() {};  

  private:
  vtkvmtkCenterlineSphereDistance(const vtkvmtkCenterlineSphereDistance&);  // Not implemented.
  void operator=(const vtkvmtkCenterlineSphereDistance&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Segmentation/itkAverageOutwardFluxImageFilter.h<|end_filename|>
/*=========================================================================

Original Method Developed By:
  Module    : EvoLib
  File      : $RCSfile: itkAverageOutwardFluxImageFilter.h,v $
  Copyright : (C)opyright (University of Zaragoza) 2005++
              See COPYRIGHT statement in top level directory.
  Authors   : <NAME> && <NAME>
  Modified  : $Author: ilarrabide $
  Purpose   : itkAverageOutwardFluxImageFilter definition.
  Date      : $Date: 2007/06/01 14:52:56 $
  Version   : $Revision: 1.3 $
  Changes   : $Locker:  $
              $Log: itkAverageOutwardFluxImageFilter.h,v $
              Revision 1.3  2007/06/01 14:52:56  ilarrabide
              Medial curve computation.

              Revision 1.2  2007/02/19 10:01:15  xmellado
              Release v1.0

Modifications Made To Support Integration Into:
	The Vascular Modeling Toolkit (VMTK)
	www.vmtk.org

Modification Authors:
	<NAME>
		University at Buffalo
		Github: rlizzo
		Date: April 12, 2018
	<NAME>
		Orobix Srl.
		Github: lantiga
		Date: April 12, 2018

=========================================================================*/

#ifndef _itkAverageOutwardFluxImageFilter_h
#define _itkAverageOutwardFluxImageFilter_h

#include <time.h>

#include <itkImage.h>
#include <itkNeighborhoodIterator.h>
#include <itkImageRegionIterator.h>

#include <itkImageToImageFilter.h>
#include <vector>

using namespace std;

namespace itk
{

/// \brief This class computes the average outward flux associated to an object implicitly 
/// represented as a distance transform. This class implements the centerline extraction 
///	algorithm described in : "S. Bouix, <NAME>, and <NAME>. Flux driven automatic centerline extraction. Technical Report
///	SOCS-04.2, School of Ccomputer Science, McGill University, 2004."

/// TODO:
/// 1. manual instantation
template< class TInputImage,
	  class TOutputPixelType = float,
	  class TInputVectorPixelType = ::itk::CovariantVector<TOutputPixelType,TInputImage::ImageDimension> > 
class ITK_EXPORT AverageOutwardFluxImageFilter:
	public ImageToImageFilter<TInputImage, ::itk::Image<TOutputPixelType,TInputImage::ImageDimension> >
{
	public:

		//-----------------------------------------------------
		// Typedefs
		//-----------------------------------------------------

		typedef typename itk::Image< TInputVectorPixelType, TInputImage::ImageDimension > TInputVectorImage;
		typedef typename itk::Image< TOutputPixelType, TInputImage::ImageDimension > TOutputImage;

		/** Standard class typedefs. */
		typedef AverageOutwardFluxImageFilter    Self;
		typedef ImageToImageFilter<TInputImage, TOutputImage> Superclass;
		typedef SmartPointer<Self> Pointer;
		typedef SmartPointer<const Self> ConstPointer;

		/** Method for creation through the object factory */
		itkNewMacro(Self);

		/** Run-time type information (and related methods). */
		itkTypeMacro( AverageOutwardFluxImageFilter, ImageToImageFilter );

		typedef typename TInputImage::ConstPointer InputConstPointerType;
		typedef typename TInputVectorImage::ConstPointer InputVectorConstPointerType;
		typedef typename TOutputImage::Pointer OutputPointerType;

		typedef itk::ImageRegionConstIterator< TInputImage > InputConstIteratorType;
		typedef itk::ConstNeighborhoodIterator< TInputVectorImage > InputVectorConstNeighborhoodIteratorType;
		typedef itk::ImageRegionIterator< TOutputImage > OutputIteratorType;

// #ifdef ITK_USE_CONCEPT_CHECKING
// 		/** Begin concept checking */
// 		itkConceptMacro(SameDimensionCheck,
// 			(Concept::SameDimension<InputImageDimension, OutputImageDimension>));
// 		itkConceptMacro(InputVectorIsReallyAVectorCheck,
// 			(Concept::HasValueType<TInputVectorPixelType>));
// 		itkConceptMacro(InputVectorIsFloatingPointCheck,
// 			(Concept::IsFloatingPoint<TInputVectorPixelType::ValueType>));
// 		//itkConceptMacro(InputVectorIsSameDimensionInputImageCheck,
// 		//	(Concept::SameDimension<TInputVectorPixelType::SizeType,InputImageDimension>));
// 		itkConceptMacro(OutputIsFloatingPointCheck,
// 			(Concept::IsFloatingPoint<TOutputPixelType>));
// 		/** End concept checking */
// #endif

		//-----------------------------------------------------
		// Methods
		//-----------------------------------------------------

		virtual void SetGradientImage(InputVectorConstPointerType gradient)
		{
			this->ProcessObject::SetNthInput( 1, const_cast< TInputVectorImage * >(gradient.GetPointer()) );
		}

		virtual InputVectorConstPointerType GetGradientImage()
		{
			return ( static_cast< TInputVectorImage *>(this->ProcessObject::GetInput(1)) );
		}
		
		/// \brief Compute the gradient.
		void GenerateData() ITK_OVERRIDE;

		void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE;

	protected:
		
		/// \brief Default Constructor
		AverageOutwardFluxImageFilter();

		/// \brief Destructor
		virtual ~AverageOutwardFluxImageFilter();


		//-----------------------------------------------------
		// Variables
		//-----------------------------------------------------

		InputConstPointerType distance;
		InputVectorConstPointerType gradient;
		OutputPointerType aof;

	private:

		AverageOutwardFluxImageFilter( const AverageOutwardFluxImageFilter& );  //purposely not implemented
		void operator = ( const AverageOutwardFluxImageFilter& );  //purposely not implemented
};

#include "itkAverageOutwardFluxImageFilter.txx"

} // end namespace itk
#endif // _itkAverageOutwardFluxImageFilter_h


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBranchSections.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkPolyDataBranchSections.h,v $
Language:  C++
Date:      $Date: 2006/10/17 15:16:16 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkPolyDataBranchSections - Extract a vessel (cross) section n-spheres distance from from the start point of a branch. 
// .SECTION Description
//  The set of vessel sections contain the profile as well as the the following information about the section:
//  - Branch Section Group Ids
//  - Branch Section Bifurcation Group Ids
//  - Branch Section Orientation
//  - Branch Section Distance Spheres
//  - Branch Section Point
//  - Branch Section Normal
//  - Branch Section Area
//  - Branch Section Min Size
//  - Branch Section Max Size
//  - Branch Section Shape
//  - Branch Section Closed

#ifndef __vtkvmtkPolyDataBranchSections_h
#define __vtkvmtkPolyDataBranchSections_h

#include "vtkPolyDataAlgorithm.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"
#include "vtkPolyData.h"

class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataBranchSections : public vtkPolyDataAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkPolyDataBranchSections,vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkPolyDataBranchSections* New();

  vtkSetStringMacro(GroupIdsArrayName);
  vtkGetStringMacro(GroupIdsArrayName);

  vtkSetObjectMacro(Centerlines,vtkPolyData);
  vtkGetObjectMacro(Centerlines,vtkPolyData);

  vtkSetStringMacro(CenterlineRadiusArrayName);
  vtkGetStringMacro(CenterlineRadiusArrayName);

  vtkSetStringMacro(CenterlineGroupIdsArrayName);
  vtkGetStringMacro(CenterlineGroupIdsArrayName);

  vtkSetStringMacro(CenterlineIdsArrayName);
  vtkGetStringMacro(CenterlineIdsArrayName);

  vtkSetStringMacro(CenterlineTractIdsArrayName);
  vtkGetStringMacro(CenterlineTractIdsArrayName);

  vtkSetStringMacro(BlankingArrayName);
  vtkGetStringMacro(BlankingArrayName);

  vtkSetStringMacro(BranchSectionAreaArrayName);
  vtkGetStringMacro(BranchSectionAreaArrayName);

  vtkSetStringMacro(BranchSectionMinSizeArrayName);
  vtkGetStringMacro(BranchSectionMinSizeArrayName);

  vtkSetStringMacro(BranchSectionMaxSizeArrayName);
  vtkGetStringMacro(BranchSectionMaxSizeArrayName);

  vtkSetStringMacro(BranchSectionShapeArrayName);
  vtkGetStringMacro(BranchSectionShapeArrayName);

  vtkSetStringMacro(BranchSectionGroupIdsArrayName);
  vtkGetStringMacro(BranchSectionGroupIdsArrayName);

  vtkSetStringMacro(BranchSectionClosedArrayName);
  vtkGetStringMacro(BranchSectionClosedArrayName);

  vtkSetStringMacro(BranchSectionDistanceSpheresArrayName);
  vtkGetStringMacro(BranchSectionDistanceSpheresArrayName);

  vtkSetMacro(NumberOfDistanceSpheres,int);
  vtkGetMacro(NumberOfDistanceSpheres,int);

  vtkSetMacro(ReverseDirection,int);
  vtkGetMacro(ReverseDirection,int);
  vtkBooleanMacro(ReverseDirection,int);

  static double ComputeBranchSectionArea(vtkPolyData* branchSection);
  static double ComputeBranchSectionShape(vtkPolyData* branchSection, double center[3], double sizeRange[2]);

  static void ExtractCylinderSection(vtkPolyData* cylinder, double origin[3], double normal[3], vtkPolyData* section, bool & closed);

  protected:
  vtkvmtkPolyDataBranchSections();
  ~vtkvmtkPolyDataBranchSections();  

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  void ComputeBranchSections(vtkPolyData* input, int groupId, vtkPolyData* output);

  vtkPolyData* Centerlines;

  char* GroupIdsArrayName;
  char* CenterlineRadiusArrayName;
  char* CenterlineGroupIdsArrayName;
  char* CenterlineIdsArrayName;
  char* CenterlineTractIdsArrayName;
  char* BlankingArrayName;

  char* BranchSectionGroupIdsArrayName;
  char* BranchSectionAreaArrayName;
  char* BranchSectionMinSizeArrayName;
  char* BranchSectionMaxSizeArrayName;
  char* BranchSectionShapeArrayName;
  char* BranchSectionClosedArrayName;
  char* BranchSectionDistanceSpheresArrayName;

  int NumberOfDistanceSpheres;
  int ReverseDirection;

  private:
  vtkvmtkPolyDataBranchSections(const vtkvmtkPolyDataBranchSections&);  // Not implemented.
  void operator=(const vtkvmtkPolyDataBranchSections&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/output.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*  output (screen, file) functions                                          */
/*                                                                           */
/*****************************************************************************/

/* renumber vertices to include the inserted ones */
void myoutputnumbervertices(struct behavior *behave,
                          struct inputs *in,
                          struct proxipool *pool)
{
    struct vertextype *vertexptr;
    struct vertex *thevertex;
    tag vertextag;
    arraypoolulong vertexnumber;

    if (improvebehave.verbosity > 4)
    {
        printf("Renumbering output vertices...\n");
    }

    vertexnumber = (arraypoolulong) 1;
    
    vertextag = proxipooliterate(pool, NOTATAG);
    while (vertextag != NOTATAG) 
    {
        vertexptr = (struct vertextype *) arraypoolforcelookup(&vertexinfo, vertextag);
        thevertex = (struct vertex *) proxipooltag2object(pool, vertextag);
        if ((vertexptr->kind != DEADVERTEX) &&
            (vertexptr->kind != UNDEADVERTEX)) 
        {
            thevertex->number = vertexnumber;
            vertexnumber++;
        }
        vertextag = proxipooliterate(pool, vertextag);
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("total of %lu vertices now...\n", vertexnumber-1);
    }
    
    globalvertexcount = vertexnumber-1;
}

/* customized vertex output TODO: this is mostly copied from Jonathan's 
   output routines */
void myoutputvertices(struct behavior *behave,
                    struct inputs *in,
                    struct proxipool *pool,
                    int argc,
                    char **argv)
{
  struct vertextype *vertexptr;
  struct vertex *thevertex;
  starreal *attributes;
  FILE *outfile;
  tag vertextag;
  arraypoolulong outvertexcount;
  arraypoolulong vertexnumber;
  arraypoolulong i;
  unsigned int j;

  outvertexcount = globalvertexcount;
  
  if (!behave->quiet && !improvebehave.animate) {
    printf("Writing %s.\n", behave->outnodefilename);
  }

  outfile = fopen(behave->outnodefilename, "w");
  if (outfile == (FILE *) NULL) {
    printf("  Error:  Cannot create file %s.\n", behave->outnodefilename);
    starexit(1);
  }

  /* Number of vertices, number of dimensions, number of vertex attributes, */
  /*   and number of boundary markers (zero or one).                        */
/*
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
  if (sizeof(arraypoolulong) > sizeof(long)) {
    fprintf(outfile, "%llu  3  %u  %d\n", (unsigned long long) outvertexcount,
            in->attribcount, 1 - behave->nobound);
  } else {
    fprintf(outfile, "%lu  3  %u  %d\n", (unsigned long) outvertexcount,
            in->attribcount, 1 - behave->nobound);
  }
#else
*/
  fprintf(outfile, "%lu  3  %u  %d\n", (unsigned long) outvertexcount,
          in->attribcount, 1 - behave->nobound);
/*
#endif
*/
  
  vertexnumber = (arraypoolulong) behave->firstnumber;
  vertextag = proxipooliterate(pool, NOTATAG);
  i = 0;
  while (vertextag != NOTATAG) {
    vertexptr = (struct vertextype *) arraypoolforcelookup(&vertexinfo, vertextag);
    thevertex = (struct vertex *) proxipooltag2object(pool, vertextag);
    if ((vertexptr->kind != DEADVERTEX) &&
        (!behave->jettison || (vertexptr->kind != UNDEADVERTEX))) {
      /* Node number, x, y, and z coordinates. */
/*
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
      if (sizeof(arraypoolulong) > sizeof(long)) {
        fprintf(outfile, "%4llu    %.17g  %.17g  %.17g",
                (unsigned long long) vertexnumber,
                (starreal) thevertex->coord[0], (starreal) thevertex->coord[1],
                (starreal) thevertex->coord[2]);
      } else {
        fprintf(outfile, "%4lu    %.17g  %.17g  %.17g",
                (unsigned long) vertexnumber,
                (starreal) thevertex->coord[0], (starreal) thevertex->coord[1],
                (starreal) thevertex->coord[2]);
      }
#else
*/
      fprintf(outfile, "%4lu    %.17g  %.17g  %.17g",
              (unsigned long) vertexnumber,
              (starreal) thevertex->coord[0], (starreal) thevertex->coord[1],
              (starreal) thevertex->coord[2]);
/*
#endif
*/
      if (in->attribcount > 0) {
        attributes = (starreal *) proxipooltag2object2(pool,
                                                       in->vertextags[i]);
        for (j = 0; j < in->attribcount; j++) {
          /* Write an attribute. */
          fprintf(outfile, "  %.17g", (starreal) attributes[j]);
        }
      }
      if (behave->nobound) {
        putc('\n', outfile);
      } else {
        /* Write the boundary marker. */
        fprintf(outfile, "    %ld\n", (long) thevertex->mark);
      }

      thevertex->number = vertexnumber;
      vertexnumber++;
    }

    vertextag = proxipooliterate(pool, vertextag);
  }

  outputfilefinish(outfile, argc, argv);
}

/* output a file with tet qualities */
void outputtetqualities(struct tetcomplex *plex,
                        struct behavior *behave,
                        char filename[],
                        int argc,
                        char **argv,
                        int qualmeasure)
{
  struct tetcomplexposition position;
  tag tet[4];
  FILE *outfile;
  arraypoolulong tetnumber;
  starreal quality;

  if (!behave->quiet && !improvebehave.animate) {
    printf("Writing %s.\n", filename);
  }

  outfile = fopen(filename, "w");
  if (outfile == (FILE *) NULL) {
    printf("  Error:  Cannot create file %s.\n", filename);
    starexit(1);
  }

  /* Number of tetrahedra, vertices per tetrahedron, attributes */
  /*   per tetrahedron.                                         */
  fprintf(outfile, "%lu  4  0\n", (unsigned long) tetcomplextetcount(plex));

  tetnumber = (arraypoolulong) behave->firstnumber;
  tetcomplexiteratorinit(plex, &position);
  tetcomplexiteratenoghosts(&position, tet);
  while (tet[0] != STOP) 
  {
    /* whether this tet is a boundary tet */
    if (boundtet(plex, tet[0], tet[1], tet[2], tet[3])) 
    {
      fprintf(outfile, "1 ");
    } else {
      fprintf(outfile, "0 ");
    }
    
    quality = tetquality(plex, tet[0], tet[1], tet[2], tet[3], qualmeasure);
    
    fprintf(outfile, "%.6g\n", quality);
    
    tetcomplexiteratenoghosts(&position, tet);
    tetnumber++;
  }

  outputfilefinish(outfile, argc, argv);
}

/* output a file with mesh surface faces */
void outputsurfacefaces(struct tetcomplex *mesh,
                        struct behavior *behave,
                        char filename[],
                        int argc,
                        char **argv)
{
  FILE *outfile;
  tag *face;
  
  struct proxipool *pool;
  struct vertex *vertexptr0;
  struct vertex *vertexptr1;
  struct vertex *vertexptr2;
  
  struct arraypool facepool;
  int numfaces = 0;
  int i;
  
  pool = mesh->vertexpool;
  
  /* allocate pool for faces */
  arraypoolinit(&(facepool), sizeof(tag)*3, LOG2TETSPERSTACKBLOCK, 0);
  /* find the surface faces */
  getsurface(mesh, &facepool, &numfaces);

  if (!behave->quiet && !improvebehave.animate) {
    printf("Writing %s.\n", filename);
  }

  outfile = fopen(filename, "w");
  if (outfile == (FILE *) NULL) {
    printf("  Error:  Cannot create file %s.\n", filename);
    starexit(1);
  }

  /* print number of faces */
  fprintf(outfile, "%d 0\n", numfaces);

  for (i=0; i<numfaces; i++)
  {
      /* fetch this face from the pool */
      face = (tag *) arraypoolfastlookup(&facepool, (unsigned long) i);
      
      vertexptr0 = (struct vertex *) proxipooltag2object(pool, face[0]);
      vertexptr1 = (struct vertex *) proxipooltag2object(pool, face[1]);
      vertexptr2 = (struct vertex *) proxipooltag2object(pool, face[2]);
      
      /* print this face to the file */
      fprintf(outfile, "%4lu  %4lu  %4lu  %4lu  \n",
        (unsigned long) i,
        (unsigned long) vertexptr0->number,
        (unsigned long) vertexptr1->number,
        (unsigned long) vertexptr2->number);
  }

  outputfilefinish(outfile, argc, argv);
  
  /* free the surface face pool */
  arraypooldeinit(&facepool);
}

/* output improvement statistics */
void outputstats(struct behavior *behave,
                 struct tetcomplex *mesh,
                 char filename[],
                 int argc,
                 char **argv)
{
  FILE *outfile;

  if (!behave->quiet && !improvebehave.animate) {
    printf("Writing %s.\n", filename);
  }

  outfile = fopen(filename, "w");
  if (outfile == (FILE *) NULL) {
    printf("  Error:  Cannot create file %s.\n", filename);
    starexit(1);
  }

  /* print options settings */
  printimproveoptionsstream(outfile, &improvebehave);

  /* print physical quality stats */
  if (improvebehave.anisotropic)
  {
      statisticsqualitystream(outfile, behave, mesh, true);
  }
  
  statisticsqualitystream(outfile, behave, mesh, false);

  /* print the improvement statistics */
  printstatsstream(outfile, mesh);
  
  /* print quadric stats */
  checkquadricsstream(outfile, mesh);
  
  outputfilefinish(outfile, argc, argv);
}

/* output a mapping from tag -> output vertex number
   TODO is this even still used? */
void outputtagmap(struct behavior *behave,
                    struct inputs *in,
                    struct proxipool *pool,
                    char filename[],
                    int argc,
                    char **argv)
{
  struct vertextype *vertexptr;
  struct vertex *thevertex;
  FILE *outfile;
  tag vertextag;
  arraypoolulong outvertexcount;
  arraypoolulong vertexnumber;
  arraypoolulong i;

  outvertexcount = globalvertexcount;
  
  if (!behave->quiet && !improvebehave.animate) {
    printf("Writing %s.\n", filename);
  }

  outfile = fopen(filename, "w");
  if (outfile == (FILE *) NULL) {
    printf("  Error:  Cannot create file %s.\n", filename);
    starexit(1);
  }

  vertexnumber = (arraypoolulong) behave->firstnumber;
  vertextag = proxipooliterate(pool, NOTATAG);
  i = 0;
  while (vertextag != NOTATAG) {
    vertexptr = (struct vertextype *) arraypoolforcelookup(&vertexinfo, vertextag);
    thevertex = (struct vertex *) proxipooltag2object(pool, vertextag);
    if ((vertexptr->kind != DEADVERTEX) &&
        (!behave->jettison || (vertexptr->kind != UNDEADVERTEX))) {
      /* Node number, x, y, and z coordinates. */
      fprintf(outfile, "%lu %4lu\n", (unsigned long) vertextag, (unsigned long) vertexnumber);
      thevertex->number = vertexnumber;
      vertexnumber++;
    }

    vertextag = proxipooliterate(pool, vertextag);
  }

  outputfilefinish(outfile, argc, argv);
}

/* output a file with animation info */
void outputanim(struct behavior *behave,
                 struct tetcomplex *mesh,
                 char filename[],
                 int passnum,
                 int passtype,
                 int passstartid,
                 int argc,
                 char **argv)
{
    FILE *outfile;
    int startindex=-1, endindex=-1, numops;

    if (!behave->quiet && !improvebehave.animate) {
        printf("Writing %s.\n", filename);
    }

    outfile = fopen(filename, "w");
    if (outfile == (FILE *) NULL) {
        printf("  Error:  Cannot create file %s.\n", filename);
        starexit(1);
    }

    /* type of pass */
    fprintf(outfile, "passtype: ");
    switch (passtype)
    {
        case SMOOTHPASS:
            fprintf(outfile, "smooth\n");
            break;
        case TOPOPASS:
            fprintf(outfile, "topo\n");
            break;
        case INSERTPASS:
            fprintf(outfile, "insert\n");
            break;
        case DESPERATEPASS:
            fprintf(outfile, "desperateinsert\n");
            break;
        case DEFORMPASS:
            fprintf(outfile, "deform\n");
            break;
        case SIZECONTROLPASS:
            fprintf(outfile, "sizecontrol\n");
            break;
        case CONTRACTALLPASS:
        case CONTRACTPASS:
            fprintf(outfile, "contract\n");
            break;
        default:
            printf("I don't know what passtype %d is, dying.", passtype);
            starexit(1);
    }
    
    /* convert from journal id's to journal indices */
    journalrangetoindex(passstartid, lastjournalentry(), &startindex, &endindex, &numops);
    assert(startindex != -1 && endindex != -1);
    
    /* journal ID before/after the pass */
    fprintf(outfile, "startid: %d\n", startindex);
    fprintf(outfile, "endid: %d\n", endindex);
    fprintf(outfile, "numops: %d\n", numops);
    /* if it's a topo pass, print out all the shit that went down */
    if (passtype == TOPOPASS)
    {
        printjournalrangestream(outfile, startindex, endindex);
    }
    /* if doing dynamic improvement, print proportion of changed volume */
    fprintf(outfile, "dynchangedvol: %g\n", stats.dynchangedvol);

    outputfilefinish(outfile, argc, argv);
}

/* print out the entire mesh. includes node positions,
   tet node values, and tet quality values */
void outputqualmesh(struct behavior *b,
                    struct inputs *in,
                    struct proxipool *vertexpool,
                    struct tetcomplex *mesh,
                    int argc,
                    char **argv,
                    int passnum,
                    int passtype,
                    int passstartid,
                    int qualmeasure)
{
    char qualfilename[300];
    char minangfilename[300];
    char maxangfilename[300];
    char vlrmsfilename[300];
    char rnrrfilename[300];
    char facefilename[300];
    char statsfilename[300];
    char animfilename[300];
    char tagmapfilename[300];
    char framenumber[10];
    int meshnumber;
    int increment;
    char workstring[FILENAMESIZE];
    int j;
    
    sprintf(framenumber, "_p%04d", passnum);
    
    increment = 0;
    /* clip off extension */
    b->innodefilename[strlen(b->innodefilename) - 5] = '\0';
    strcpy(workstring, b->innodefilename);
    /* Find the last period in the filename. */
    j = 1;
    while (workstring[j] != '\0') {
      if ((workstring[j] == '.') && 
          (workstring[j + 1] != '\0') && 
          (workstring[j + 1] != '/') && 
          (workstring[j + 1] != '\\') &&
          (workstring[j + 1] != '.')) {
        increment = j + 1;
      }
      j++;
    }
    
    /* The iteration number is zero by default, unless there's an iteration */
    /*   number in the filename.                                            */
    meshnumber = 0;
    if (increment > 0) {
      /* Read the iteration number from the end of the filename. */
      j = increment;
      do {
        if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
          
          meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
        } else {
          /* Oops, not a digit; this isn't an iteration number after all. */
          meshnumber = 0;
          break;
        }
        j++;
      } while (workstring[j] != '\0');
    }
    
    if (increment == 0)
    {
        increment = strlen(b->innodefilename);
        workstring[increment] = '.';
        increment++;
    }
    
    workstring[increment] = '%';
    workstring[increment + 1] = 'd';
    workstring[increment + 2] = '\0';
    sprintf(b->innodefilename, workstring, meshnumber + 1);
    
    /* create custome output filename */
    if (passnum == 0 && argv !=NULL)
    {
        /* copy the specified prefix into temp */
        if (strcmp(improvebehave.fileprefix,"") != 0)
        {
            strcpy(b->innodefilename, improvebehave.fileprefix);
        }
    }
    
    /* node file name */
    strcpy(b->outnodefilename, b->innodefilename);
    if (improvebehave.animate)
    {
        strcat(b->outnodefilename, framenumber);
    }
    strcat(b->outnodefilename, ".node");
    
    /* ele file name */
    strcpy(b->outelefilename, b->innodefilename);
    if (improvebehave.animate)
    {
        strcat(b->outelefilename, framenumber);
    }
    strcat(b->outelefilename, ".ele");
    
    /* face file name */
    strcpy(facefilename, b->innodefilename);
    if (improvebehave.animate)
    {
        strcat(facefilename, framenumber);
    }
    strcat(facefilename, ".face");
    
    /* quality file name */
    strcpy(qualfilename, b->innodefilename);
    if (improvebehave.animate)
    {
        strcat(qualfilename, framenumber);
    }
    strcat(qualfilename, ".minsine");
    
    /* minimum angle file name */
    strcpy(minangfilename, b->innodefilename);
    if (improvebehave.animate)
    {
        strcat(minangfilename, framenumber);
    }
    strcat(minangfilename, ".minang");
    
    /* maximum angle file name */
    strcpy(maxangfilename, b->innodefilename);
    if (improvebehave.animate)
    {
        strcat(maxangfilename, framenumber);
    }
    strcat(maxangfilename, ".maxang");
    
    /* vlrms file name */
    strcpy(vlrmsfilename, b->innodefilename);
    if (improvebehave.animate)
    {
        strcat(vlrmsfilename, framenumber);
    }
    strcat(vlrmsfilename, ".vlrms");
    
    /* rnrr file name */
    strcpy(rnrrfilename, b->innodefilename);
    if (improvebehave.animate)
    {
        strcat(rnrrfilename, framenumber);
    }
    strcat(rnrrfilename, ".nrr");
    
    /* stats file name */
    strcpy(statsfilename, b->innodefilename);
    if (improvebehave.animate)
    {
        strcat(statsfilename, framenumber);
    }
    strcat(statsfilename, ".stats");
    
    /* animation file name */
    if (improvebehave.animate && passnum != 0)
    {
        strcpy(animfilename, b->innodefilename);
        strcat(animfilename, framenumber);
        strcat(animfilename, ".anim");
        strcpy(tagmapfilename, b->innodefilename);
        strcat(tagmapfilename, framenumber);
        strcat(tagmapfilename, ".tagmap");
    }
    
    /* don't output bulky information if all we want is stats for timeseries */
    if (improvebehave.timeseries == 0)
    {
        /* renumber vertices */
        myoutputnumbervertices(b, in, vertexpool);
    
        /* output vertices */
        myoutputvertices(b, in, vertexpool, argc, argv);
    
        /* output tetrahedra */
        outputtetrahedra(b, in, mesh, argc, argv);
    
        /* output surface faces */
        outputsurfacefaces(mesh, b, facefilename, argc, argv);
    
        /* output tetrahedra -> quality mapping */
        if (improvebehave.minsineout)
        {
            outputtetqualities(mesh, b, qualfilename, argc, argv, QUALMINSINE);
        }
        
        /* output tetrahedra -> minimum angle mapping */
        if (improvebehave.minangout)
        {
            outputtetqualities(mesh, b, minangfilename, argc, argv, QUALMINANGLE);
        }
        
        /* output tetrahedra -> maximum angle mapping */
        if (improvebehave.maxangout)
        {
            outputtetqualities(mesh, b, maxangfilename, argc, argv, QUALMAXANGLE);
        }
        
        /* output tetrahedra -> maximum angle mapping */
        if (improvebehave.vlrmsout)
        {
            outputtetqualities(mesh, b, vlrmsfilename, argc, argv, QUALVLRMS3RATIO);
        }
        
        /* output tetrahedra -> maximum angle mapping */
        if (improvebehave.nrrout)
        {
            outputtetqualities(mesh, b, rnrrfilename, argc, argv, QUALRADIUSRATIO);
        }
    }
    
    /* output improvement stats */
    outputstats(b, mesh, statsfilename, argc, argv);
    
    /* output animation info from previous frame to this one */
    if (improvebehave.animate && passnum != 0 && improvebehave.timeseries == 0)
    {
        outputanim(b, mesh, animfilename, passnum, passtype, passstartid, argc, argv);
        outputtagmap(b, in, vertexpool, tagmapfilename, argc, argv);
    }
}


<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataManifoldStencil.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkPolyDataManifoldStencil.cxx,v $
  Language:  C++
  Date:      $Date: 2005/11/15 17:39:25 $
  Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataManifoldStencil.h"
#include "vtkvmtkPolyDataManifoldExtendedNeighborhood.h"
#include "vtkvmtkPolyDataManifoldNeighborhood.h"

#include "vtkObjectFactory.h"
#include "vtkIdList.h"
#include "vtkCell.h"
#include "vtkvmtkMath.h"
#include "vtkMath.h"



vtkvmtkPolyDataManifoldStencil::vtkvmtkPolyDataManifoldStencil()
  {
  this->Area = 0.0;
  this->NumberOfComponents = 1;
  this->UseExtendedNeighborhood = 1;
  }

void vtkvmtkPolyDataManifoldStencil::ComputeArea()
  {
  double point[3], point1[3], point2[3];
  vtkIdType j, numberOfTriangles;

  if (this->DataSet==NULL)
    {
    vtkErrorMacro(<<"No DataSet specified.");
    return;
    }

  this->DataSet->GetPoint(this->DataSetPointId,point);
  this->Area = 0.0;

  if (!this->IsBoundary)
    {
    numberOfTriangles = this->NPoints;
    }
  else
    {
    numberOfTriangles = this->NPoints-1;
    }

  for (j=0; j<numberOfTriangles; j++)
    {
    this->DataSet->GetPoint(this->PointIds[j],point1);
    this->DataSet->GetPoint(this->PointIds[(j+1)%this->NPoints],point2);
		
    this->Area += vtkvmtkMath::TriangleArea(point2,point,point1);
    }
  }

void vtkvmtkPolyDataManifoldStencil::ScaleWithAreaFactor(double factor)
  {
  double scale;

  if (this->Area<VTK_VMTK_DOUBLE_TOL)
    {
    scale = 2.0*VTK_VMTK_LARGE_DOUBLE;
    }
  else
    {
    scale = 1.0 / (this->Area * factor);
    }

  this->ScaleWeights(scale);
  }


void vtkvmtkPolyDataManifoldStencil::Build()
  {
  if (this->PointIds && this->Weights && !this->ReallocateOnBuild)
    {
    return;
    }
  
  vtkIdType i;
  vtkvmtkPolyDataManifoldNeighborhood *manifoldNeighborhood;

  if (this->UseExtendedNeighborhood)
    {
    manifoldNeighborhood = vtkvmtkPolyDataManifoldExtendedNeighborhood::New();
    }
  else
    {
    manifoldNeighborhood = vtkvmtkPolyDataManifoldNeighborhood::New();
    }
  manifoldNeighborhood->SetDataSet(this->DataSet);
  manifoldNeighborhood->SetDataSetPointId(this->DataSetPointId);
  manifoldNeighborhood->Build();

  this->NPoints = manifoldNeighborhood->GetNumberOfPoints();
  if (this->PointIds!=NULL)
    {
    delete[] this->PointIds;
    this->PointIds = NULL;
    }
  this->PointIds = new vtkIdType[this->NPoints];
  memcpy(this->PointIds,manifoldNeighborhood->GetPointer(0),this->NPoints*sizeof(vtkIdType));

  this->IsBoundary = manifoldNeighborhood->GetIsBoundary();

  if (this->Weights!=NULL)
    {
    delete[] this->Weights;
    this->Weights = NULL;
    }
  this->Weights = new double[this->NumberOfComponents*this->NPoints];
  for (i=0; i<this->NumberOfComponents*this->NPoints; i++)
    {
    this->Weights[i] = 0.0;
    }
  this->CenterWeight = new double[this->NumberOfComponents];
  for (i=0; i<this->NumberOfComponents; i++)
    {
    this->CenterWeight[i] = 0.0;
    }

  manifoldNeighborhood->Delete();
  }

void vtkvmtkPolyDataManifoldStencil::DeepCopy(vtkvmtkPolyDataManifoldStencil *src)
  {
  this->Superclass::DeepCopy(src);
  this->Area = src->Area;
  }


<|start_filename|>vtkVmtk/IO/vtkvmtkPNGWriter.cxx<|end_filename|>
/*=========================================================================
                                                                                                                                    
Program:   VMTK
Module:    $RCSfile: vtkvmtkPNGWriter.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:47:47 $
Version:   $Revision: 1.6 $
                                                                                                                                    
  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.
                                                                                                                                    
=========================================================================*/

#include "vtkvmtkPNGWriter.h"
#include "vtkUnsignedCharArray.h"
#include "vtkImageData.h"
#include "vtkPointData.h"
#include "vtkErrorCode.h"
#include "vtkObjectFactory.h"
#include "vtkVersion.h"
#if (VTK_MAJOR_VERSION > 5)
#include "vtkInformation.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#endif

#include <math.h>

#include <string.h>

//<NAME>, http://episec.com/people/edelkind/

char b64string[] =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

long base64_encode (char* to, char* from, unsigned int len)
{
  char *fromp = from;
  char *top = to;
  unsigned char cbyte;
  unsigned char obyte;
  char end[3];

  for (; len >= 3; len -= 3) {
    cbyte = *fromp++;
    *top++ = b64string[(int)(cbyte >> 2)];
    obyte = (cbyte << 4) & 0x30;    /* 0011 0000 */

    cbyte = *fromp++;
    obyte |= (cbyte >> 4);      /* 0000 1111 */
    *top++ = b64string[(int)obyte];
    obyte = (cbyte << 2) & 0x3C;    /* 0011 1100 */

    cbyte = *fromp++;
    obyte |= (cbyte >> 6);      /* 0000 0011 */
    *top++ = b64string[(int)obyte];
    *top++ = b64string[(int)(cbyte & 0x3F)];/* 0011 1111 */
  }

  if (len) {
    end[0] = *fromp++;
    if (--len) end[1] = *fromp++; else end[1] = 0;
    end[2] = 0;

    cbyte = end[0];
    *top++ = b64string[(int)(cbyte >> 2)];
    obyte = (cbyte << 4) & 0x30;    /* 0011 0000 */

    cbyte = end[1];
    obyte |= (cbyte >> 4);
    *top++ = b64string[(int)obyte];
    obyte = (cbyte << 2) & 0x3C;    /* 0011 1100 */

    if (len) *top++ = b64string[(int)obyte];
    else *top++ = '=';
    *top++ = '=';
  }
  *top = 0;
  return top - to;
}


vtkStandardNewMacro(vtkvmtkPNGWriter);

vtkvmtkPNGWriter::vtkvmtkPNGWriter()
{
  this->Base64Image = NULL;
  this->WriteToBase64 = 0;
  this->FlipImage = 0;
}

vtkvmtkPNGWriter::~vtkvmtkPNGWriter()
{
  if (this->Base64Image)
    {
    delete[] this->Base64Image;
    this->Base64Image = NULL;
    }
}

void vtkvmtkPNGWriter::Write()
{
  if (!this->WriteToBase64) {
    Superclass::Write();
    return;
  }

  int previousWriteToMemory = this->GetWriteToMemory();

  this->WriteToMemoryOn();

  //Superclass::Write();

  this->SetErrorCode(vtkErrorCode::NoError);

  // Error checking
  if ( this->GetInput() == NULL )
    {
    vtkErrorMacro(<<"Write:Please specify an input!");
    return;
    }
  if (!this->WriteToMemory && !this->GetFileName() && !this->GetFilePattern())
    {
    vtkErrorMacro(<<"Write:Please specify either a FileName or a file prefix and pattern");
    this->SetErrorCode(vtkErrorCode::NoFileNameError);
    return;
    }

  // Make sure the file name is allocated
  this->InternalFileName =
    new char[(this->GetFileName() ? strlen(this->GetFileName()) : 1) +
            (this->GetFilePrefix() ? strlen(this->GetFilePrefix()) : 1) +
            (this->GetFilePattern() ? strlen(this->GetFilePattern()) : 1) + 10];

  // Fill in image information.
  int *wExtent;
#if (VTK_MAJOR_VERSION <= 5)
  this->GetInput()->UpdateInformation();
  wExtent = this->GetInput()->GetWholeExtent();
#else
  this->UpdateInformation();
  vtkInformation *inInfoImage = this->GetInputPortInformation(0);
  inInfoImage->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wExtent);
#endif

  this->FileNumber = wExtent[4];
  this->MinimumFileNumber = this->MaximumFileNumber = this->FileNumber;
  this->FilesDeleted = 0;
  this->UpdateProgress(0.0);
  // loop over the z axis and write the slices
  for (this->FileNumber = wExtent[4]; this->FileNumber <= wExtent[5];
       ++this->FileNumber)
    {
    this->MaximumFileNumber = this->FileNumber;
    int updatedExtent[6] = {wExtent[0], wExtent[1],
                            wExtent[2], wExtent[3],
                            this->FileNumber,
                            this->FileNumber};
#if (VTK_MAJOR_VERSION <= 5)
    this->GetInput()->SetUpdateExtent(updatedExtent);
#endif
    // determine the name
    if (this->GetFileName())
      {
      sprintf(this->InternalFileName,"%s",this->GetFileName());
      }
    else
      {
      if (this->GetFilePrefix())
        {
        sprintf(this->InternalFileName, this->GetFilePattern(),
                this->GetFilePrefix(), this->FileNumber);
        }
      else
        {
        sprintf(this->InternalFileName, this->GetFilePattern(), this->FileNumber);
        }
      }
#if (VTK_MAJOR_VERSION <= 5)
    this->GetInput()->UpdateData();
#endif
    
    if (!this->FlipImage)
      {
#if (VTK_MAJOR_VERSION <= 5)
      this->WriteSlice(this->GetInput());
#else
      this->WriteSlice(this->GetInput(), updatedExtent);
#endif
      }
    else
      {
      vtkImageData* flippedInput = vtkImageData::New();
      flippedInput->DeepCopy(this->GetInput());
#if (VTK_MAJOR_VERSION <= 5)
      flippedInput->SetUpdateExtent(updatedExtent);
#endif
      vtkDataArray* inputArray = this->GetInput()->GetPointData()->GetScalars();
      vtkDataArray* flippedInputArray = flippedInput->GetPointData()->GetScalars();
      for (int i=0; i<wExtent[3]-wExtent[2]+1; i++)
        {
        for (int j=0; j<wExtent[1]-wExtent[0]+1; j++)
          {
          flippedInputArray->SetTuple((wExtent[3]-wExtent[2]-i)*(wExtent[1]-wExtent[0]+1)+j,inputArray->GetTuple(i*(wExtent[1]-wExtent[0]+1)+j));
          }
        }
#if (VTK_MAJOR_VERSION <= 5)
      this->WriteSlice(flippedInput);
#else
      this->WriteSlice(flippedInput, updatedExtent);
#endif
      flippedInput->Delete();
      }

    if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
      {
      this->DeleteFiles();
      break;
      }
    this->UpdateProgress((this->FileNumber - wExtent[4])/
                         (wExtent[5] - wExtent[4] + 1.0));
    }
  delete [] this->InternalFileName;
  this->InternalFileName = NULL;

  vtkUnsignedCharArray* result = this->GetResult();
  char* data = (char*)result->GetPointer(0);
  int length = result->GetNumberOfTuples() * result->GetNumberOfComponents();

  char* flipped_data = new char[length];
  if (this->FlipImage)
    {
    for (int i=0; i<length; i++)
      {
      flipped_data[i] = data[length-i-1];
      }
    data = flipped_data;
    }

  char* encoded_data = new char[2*length];
  int output_length = base64_encode(encoded_data,data,length);
  this->SetBase64Image(encoded_data);

  delete[] encoded_data;
  delete[] flipped_data;

  this->SetWriteToMemory(previousWriteToMemory);
} 

void vtkvmtkPNGWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkPNGWriter::PrintSelf(os,indent);
}


<|start_filename|>distribution/legacy/nsis/vmtk-startup.bat<|end_filename|>
rem @echo off
set VMTK_DIR=%~dp0
set PATH=%VMTK_DIR%bin;%VMTK_DIR%lib\InsightToolkit;%VMTK_DIR%lib\Python;%PATH%
set PYTHONPATH=%VMTK_DIR%lib\site-packages;%VMTK_DIR%lib\vtk-5.6;%VMTK_DIR%lib\vmtk
cd %VMTK_DIR%
python bin\vmtk-exe.py


<|start_filename|>vtkVmtk/Misc/vtkvmtkBoundaryLayerGenerator.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkBoundaryLayerGenerator.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:47:48 $
Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkBoundaryLayerGenerator - Generates boundary layers of prismatic elements by warping a surface mesh.
// .SECTION Description
// ...

#ifndef __vtkvmtkBoundaryLayerGenerator_h
#define __vtkvmtkBoundaryLayerGenerator_h

#include "vtkUnstructuredGridAlgorithm.h"
#include "vtkvmtkWin32Header.h"

class vtkPoints;
class vtkUnsignedCharArray;
class vtkDataArray;

class VTK_VMTK_MISC_EXPORT vtkvmtkBoundaryLayerGenerator : public vtkUnstructuredGridAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkBoundaryLayerGenerator,vtkUnstructuredGridAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkBoundaryLayerGenerator *New();
  
  vtkGetStringMacro(WarpVectorsArrayName);
  vtkSetStringMacro(WarpVectorsArrayName);

  vtkGetStringMacro(LayerThicknessArrayName);
  vtkSetStringMacro(LayerThicknessArrayName);

  vtkGetMacro(UseWarpVectorMagnitudeAsThickness,int);
  vtkSetMacro(UseWarpVectorMagnitudeAsThickness,int);
  vtkBooleanMacro(UseWarpVectorMagnitudeAsThickness,int);

  vtkGetMacro(ConstantThickness,int);
  vtkSetMacro(ConstantThickness,int);
  vtkBooleanMacro(ConstantThickness,int);

  vtkGetMacro(IncludeSurfaceCells,int);
  vtkSetMacro(IncludeSurfaceCells,int);
  vtkBooleanMacro(IncludeSurfaceCells,int);

  vtkGetMacro(IncludeSidewallCells,int);
  vtkSetMacro(IncludeSidewallCells,int);
  vtkBooleanMacro(IncludeSidewallCells,int);

  vtkGetMacro(NegateWarpVectors,int);
  vtkSetMacro(NegateWarpVectors,int);
  vtkBooleanMacro(NegateWarpVectors,int);

  vtkGetMacro(LayerThickness,double);
  vtkSetMacro(LayerThickness,double);

  vtkGetMacro(LayerThicknessRatio,double);
  vtkSetMacro(LayerThicknessRatio,double);

  vtkGetMacro(MaximumLayerThickness,double);
  vtkSetMacro(MaximumLayerThickness,double);

  vtkGetMacro(NumberOfSubLayers,int);
  vtkSetMacro(NumberOfSubLayers,int);

  vtkGetMacro(SubLayerRatio,double);
  vtkSetMacro(SubLayerRatio,double);

  vtkGetMacro(NumberOfSubsteps,int);
  vtkSetMacro(NumberOfSubsteps,int);

  vtkGetMacro(Relaxation,double);
  vtkSetMacro(Relaxation,double);

  vtkGetMacro(LocalCorrectionFactor,double);
  vtkSetMacro(LocalCorrectionFactor,double);

  vtkSetStringMacro(CellEntityIdsArrayName);
  vtkGetStringMacro(CellEntityIdsArrayName);

  vtkGetMacro(InnerSurfaceCellEntityId,int);
  vtkSetMacro(InnerSurfaceCellEntityId,int);

  vtkGetMacro(OuterSurfaceCellEntityId,int);
  vtkSetMacro(OuterSurfaceCellEntityId,int);

  vtkGetMacro(SidewallCellEntityId,int);
  vtkSetMacro(SidewallCellEntityId,int);

  vtkGetMacro(VolumeCellEntityId,int);
  vtkSetMacro(VolumeCellEntityId,int);

  vtkGetObjectMacro(InnerSurface,vtkUnstructuredGrid);

  protected:
  vtkvmtkBoundaryLayerGenerator();
  ~vtkvmtkBoundaryLayerGenerator();

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  void BuildWarpVectors(vtkUnstructuredGrid* input);
  void IncrementalWarpPoints(vtkUnstructuredGrid* input, vtkPoints* basePoints, vtkPoints* warpedPoints, int substep, int numberOfSubsteps, double relaxation);
  void IncrementalWarpVectors(vtkUnstructuredGrid* input, int numberOfSubsteps, double relaxation);
  int CheckTangle(vtkUnstructuredGrid* input, vtkUnsignedCharArray* checkArray);
  void LocalUntangle(vtkUnstructuredGrid* input, vtkUnsignedCharArray* checkArray, double alpha); 
  void WarpPoints(vtkPoints* inputPoints, vtkPoints* warpedPoints, int subLayerId, bool quadratic);
  void UnwrapSublayers(vtkUnstructuredGrid* input, vtkPoints* outputPoints);

  vtkDataArray* WarpVectorsArray;
  vtkDataArray* LayerThicknessArray;

  int UseWarpVectorMagnitudeAsThickness;
  int ConstantThickness;

  char* WarpVectorsArrayName;
  char* LayerThicknessArrayName;

  double LayerThickness;
  double LayerThicknessRatio;
  double MaximumLayerThickness;

  int NumberOfSubLayers;
  int NumberOfSubsteps;
  double SubLayerRatio;

  int IncludeSurfaceCells;
  int IncludeSidewallCells;
  int NegateWarpVectors;

  vtkUnstructuredGrid* InnerSurface;

  char* CellEntityIdsArrayName;
  int InnerSurfaceCellEntityId;
  int OuterSurfaceCellEntityId;
  int SidewallCellEntityId;
  int VolumeCellEntityId;

  double Relaxation;
  double LocalCorrectionFactor;

  private:
  vtkvmtkBoundaryLayerGenerator(const vtkvmtkBoundaryLayerGenerator&);  // Not implemented.
  void operator=(const vtkvmtkBoundaryLayerGenerator&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridGradientFilter.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkUnstructuredGridGradientFilter.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:44 $
  Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkUnstructuredGridGradientFilter - Compute the gradient of data stored within an unstructured grid mesh.
// .SECTION Description
// ..

#ifndef __vtkvmtkUnstructuredGridGradientFilter_h
#define __vtkvmtkUnstructuredGridGradientFilter_h

#include "vtkvmtkWin32Header.h"
#include "vtkUnstructuredGridAlgorithm.h"

class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkUnstructuredGridGradientFilter : public vtkUnstructuredGridAlgorithm
{
public:
  static vtkvmtkUnstructuredGridGradientFilter* New();
  vtkTypeMacro(vtkvmtkUnstructuredGridGradientFilter,vtkUnstructuredGridAlgorithm);

  vtkSetStringMacro(InputArrayName);
  vtkGetStringMacro(InputArrayName);

  vtkSetStringMacro(GradientArrayName);
  vtkGetStringMacro(GradientArrayName);

  vtkSetMacro(ConvergenceTolerance,double);
  vtkGetMacro(ConvergenceTolerance,double);

  vtkSetMacro(QuadratureOrder,int);
  vtkGetMacro(QuadratureOrder,int);

  vtkSetMacro(ComputeIndividualPartialDerivatives,int);
  vtkGetMacro(ComputeIndividualPartialDerivatives,int);
  vtkBooleanMacro(ComputeIndividualPartialDerivatives,int);

protected:
  vtkvmtkUnstructuredGridGradientFilter();
  ~vtkvmtkUnstructuredGridGradientFilter();

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  char* InputArrayName;
  char* GradientArrayName;
  double ConvergenceTolerance;
  int QuadratureOrder;
  int ComputeIndividualPartialDerivatives;

private:
  vtkvmtkUnstructuredGridGradientFilter(const vtkvmtkUnstructuredGridGradientFilter&);  // Not implemented.
  void operator=(const vtkvmtkUnstructuredGridGradientFilter&);  // Not implemented.
};

#endif



<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyBall.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkPolyBall.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:46:43 $
Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkPolyBall - An instance of vtkImplicitFunction which evaluates the minimum sphere function from a collection of points with attached sphere radii as point data.
// .SECTION Description
// Implicit functions are real valued functions defined in 3D space, w = F(x,y,z). Two primitive operations are required: the ability to evaluate the function, and the function gradient at a given point. The implicit function divides space into three regions: on the surface (F(x,y,z)=w), outside of the surface (F(x,y,z)>c), and inside the surface (F(x,y,z)<c). (When c is zero, positive values are outside, negative values are inside, and zero is on the surface. Note also that the function gradient points from inside to outside.)
//  
// A polyball is just an implicit function which takes a data set containing a bunch of points in R^3 with sphere radii defined on top of them and evaluates the minimum sphere function across the entire collection for a particular point. The sphere function is zero at the sphere surface, negative inside the sphere, and positive outside the sphere. This is implemented as a brute force calculation; in order to find the minimum sphere function across the collection, the sphere function is evaluated at the query point for every point in the input data set. 

#ifndef __vtkvmtkPolyBall_h
#define __vtkvmtkPolyBall_h

#include "vtkImplicitFunction.h"
#include "vtkPolyData.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyBall : public vtkImplicitFunction
{
  public:
  vtkTypeMacro(vtkvmtkPolyBall,vtkImplicitFunction);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE;

  static vtkvmtkPolyBall *New();

  // Description
  // Evaluate polyball.
  double EvaluateFunction(double x[3]) VTK_OVERRIDE;
  double EvaluateFunction(double x, double y, double z) VTK_OVERRIDE
  {return this->vtkImplicitFunction::EvaluateFunction(x, y, z); } ;

  // Description
  // Evaluate polyball gradient.
  void EvaluateGradient(double x[3], double n[3]) VTK_OVERRIDE;

  // Description:
  // Set / get input poly data.
  vtkSetObjectMacro(Input,vtkPolyData);
  vtkGetObjectMacro(Input,vtkPolyData);
  void SetInputData(vtkPolyData* input) { SetInput(input); }
  vtkPolyData* GetInputData() { return GetInput(); }

  // Description:
  // Set / get poly ball radius array name.
  vtkSetStringMacro(PolyBallRadiusArrayName);
  vtkGetStringMacro(PolyBallRadiusArrayName);

  // Description:
  // Get the id of the last nearest poly ball center.
  vtkGetMacro(LastPolyBallCenterId,vtkIdType);

  protected:
  vtkvmtkPolyBall();
  ~vtkvmtkPolyBall();

  vtkPolyData* Input;
  char* PolyBallRadiusArrayName;
  vtkIdType LastPolyBallCenterId;

  private:
  vtkvmtkPolyBall(const vtkvmtkPolyBall&);  // Not implemented.
  void operator=(const vtkvmtkPolyBall&);  // Not implemented.
};

#endif




<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineSmoothing.h<|end_filename|>
/*=========================================================================

Program:   VTK Blood Vessel Smoothing
Module:    $RCSfile: vtkvmtkCenterlineSmoothing.h,v $
Language:  C++
Date:      $Date: 2006/07/17 09:52:56 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkCenterlineSmoothing - iteratively smooth a centerline with a laplacian kernel 
// .SECTION Description
// ...

#ifndef __vtkvmtkCenterlineSmoothing_h
#define __vtkvmtkCenterlineSmoothing_h

#include "vtkPolyDataAlgorithm.h"
//#include "vtkvmtkComputationalSmoothingWin32Header.h"
#include "vtkvmtkWin32Header.h"

class vtkDoubleArray;

class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineSmoothing : public vtkPolyDataAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkCenterlineSmoothing,vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkCenterlineSmoothing* New();

  vtkSetMacro(SmoothingFactor,double);
  vtkGetMacro(SmoothingFactor,double);

  vtkSetMacro(NumberOfSmoothingIterations,int);
  vtkGetMacro(NumberOfSmoothingIterations,int);

  static void SmoothLine(vtkPoints* linePoints, vtkPoints* smoothLinePoints, int numberOfIterations = 10, double relaxation = 0.1);

  protected:
  vtkvmtkCenterlineSmoothing();
  ~vtkvmtkCenterlineSmoothing();  

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  double SmoothingFactor;
  int NumberOfSmoothingIterations;

  private:
  vtkvmtkCenterlineSmoothing(const vtkvmtkCenterlineSmoothing&);  // Not implemented.
  void operator=(const vtkvmtkCenterlineSmoothing&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/anisotropy.c<|end_filename|>
/* Functions to transform space for anisotropic meshing */

/* given a single vector, return two more that are mutually
   orthogonal to it */
void getorthobasis(starreal v1[3],
                   starreal v2[3],
                   starreal v3[3])
{
    starreal invLen;
    
    if (fabs(v1[0]) > fabs(v1[1]))
    {
        invLen = 1.0 / sqrt(v1[0] * v1[0] + v1[2] * v1[2]);
        v2[0] = -v1[2] * invLen;
        v2[1] = 0.0;
        v2[2] = v1[0] * invLen;
    }
    else
    {
        invLen = 1.0 / sqrt(v1[1] * v1[1] + v1[2] * v1[2]);
        v2[0] = 0.0;
        v2[1] = v1[2] * invLen;
        v2[2] = -v1[1] * invLen;
    }
    cross(v1, v2, v3);
    
    assert(vlength(v1) > 0.0);
    assert(vlength(v2) > 0.0);
    assert(vlength(v3) > 0.0);
}

/* given three mutually orthogonal vectors and three corresponding
   eigenvalues, compute a transformation matrix E */
void tensorfromeigen(starreal v1[3],
                     starreal v2[3],
                     starreal v3[3],
                     starreal e1,
                     starreal e2,
                     starreal e3,
                     starreal E[3][3])
{
    starreal v1n[3], v2n[3], v3n[3];
    int i, j;
    
    /* normalize the basis vectors and scale them */
    vscale(e1 / vlength(v1), v1, v1n);
    vscale(e2 / vlength(v2), v2, v2n);
    vscale(e3 / vlength(v3), v3, v3n);
    
    /* compute transformation matrix */
    /* E = (v1 * v1') * e1 + (v2 * v2') * e2 + (v3 * v3') * e3 */
    for (i=0; i<3; i++)
    {
        for (j=0; j<3; j++)
        {
            E[i][j] = (v1n[i] * v1n[j]) + (v2n[i] * v2n[j]) + (v3n[i] * v3n[j]);
        }
    }
}

/* tensor field that compresses space orthogonal to lines radiating
   from the origin */
void sinktensor(starreal x,
                starreal y,
                starreal z,
                starreal E[3][3])
{
    starreal s;
    starreal v1[3], v2[3], v3[3];
    
    s = 2.0 * sqrt(x*x + y*y + z*z);
    /* check whether we're at the origin */
    if (s < 1.e-13)
    {
        x = 1.0;
        y = z = 0.0;
    }
    if (s > 1.0) s = 1.0;
    s += 0.8;
    
    /* set the scaled vector to be radially outward */
    v1[0] = x;
    v1[1] = y;
    v1[2] = z;
    assert(vlength(v1) > 0.0);
    
    /* find an orthogonal basis for this vector */
    getorthobasis(v1, v2, v3);
    
    /* build deformation tensor */
    tensorfromeigen(v1, v2, v3, 1.0, s, s, E);
}

/* tensor field that compresses space orthogonal to lines radiating
   from the origin */
void swirltensor(starreal x,
                 starreal y,
                 starreal z,
                 starreal E[3][3])
{
    starreal s;
    starreal v1[3], v2[3], v3[3];
    
    s = 5.0 * sqrt(x*x + y*y + z*z);
    /* check whether we're at the origin */
    if (s < 1.e-13)
    {
        x = 1.0;
        y = z = 0.0;
    }
    if (s > 1.0) s = 1.0;
    s += 1.0;
    
    /* set the scaled vector to be radially outward */
    v1[0] = x;
    v1[1] = y;
    v1[2] = z;
    
    /* find an orthogonal basis for this vector */
    getorthobasis(v1, v2, v3);
    
    /* build deformation tensor */
    tensorfromeigen(v1, v2, v3, s, 1.0, 1.0, E);
}

/* tensor field that runs sin(x) */
void sinetensor(starreal x,
                starreal y,
                starreal z,
                starreal E[3][3])
{
    starreal s;
    starreal v1[3], v2[3], v3[3];
    
    /*starreal period = 6.0;*/
    starreal period = 6.0;
    starreal scale = 1.8;
    
    /* let the y direction the vector be the derivative of sin(x), which is cos(x) */
    v1[0] = 1.0;
    v1[1] = scale * cos(x * period);
    v1[2] = 0.0;
    
    /* normalize */
    vscale(1.0 / vlength(v1), v1, v1);
    
    /* we'll scale the tensor down as it moves away from sin(x) */
    /*
    s = 1.0 / (0.6 + fabs(y*y - ((scale * sin(x * period)) * (scale * sin(x * period)))));
    s += 1.0;
    */
    /* nah, actually */
    s = 2.3;
    s = 2.1;
    
    /* find an orthogonal basis for this vector */
    getorthobasis(v1, v2, v3);
    
    if (improvebehave.verbosity > 6)
    {
        printf("in sine tensor, point is [%g %g %g], v1 = [%g %g %g], s = %g, sin(x)=%g, cos(x)=%g\n", x, y, z, v1[0], v1[1], v2[2], s, sin(x), cos(x));
    }
    
    /* build deformation tensor */
    /*
    tensorfromeigen(v1, v2, v3, 1.0, s, s, E);
    */
    /* norm */
    tensorfromeigen(v1, v2, v3, 1.0/s, 1.0, 1.0, E);
}

/* tensor with denser elements in the middle */
void centertensor(starreal x,
                  starreal y,
                  starreal z,
                  starreal E[3][3])
{
    starreal s;
    
    s = 0.7 + 3.0 / (sqrt(x*x + y*y + z*z) + 0.4);
    
    E[0][0] = s; E[0][1] = 0.0; E[0][2] = 0.0;
    E[1][0] = 0.0; E[1][1] = s; E[1][2] = 0.0;
    E[2][0] = 0.0; E[2][1] = 0.0; E[2][2] = s;
}

/* tensor with denser elements away from the middle */
void perimetertensor(starreal x,
                     starreal y,
                     starreal z,
                     starreal E[3][3])
{
    starreal s;
    
    s = (sqrt(x*x + y*y + z*z) + 0.2);
    
    E[0][0] = s; E[0][1] = 0.0; E[0][2] = 0.0;
    E[1][0] = 0.0; E[1][1] = s; E[1][2] = 0.0;
    E[2][0] = 0.0; E[2][1] = 0.0; E[2][2] = s;
}

/* tensor with denser elements on the +x side */
void righttensor(starreal x,
                 starreal y,
                 starreal z,
                 starreal E[3][3])
{
    starreal s;
    
    s = (x + 1.0);
    if (s < 1.0) s = 1.0;
    
    E[0][0] = s; E[0][1] = 0.0; E[0][2] = 0.0;
    E[1][0] = 0.0; E[1][1] = s; E[1][2] = 0.0;
    E[2][0] = 0.0; E[2][1] = 0.0; E[2][2] = s;
}

void scaletensor(starreal scalex,
                 starreal scaley,
                 starreal scalez,
                 starreal E[3][3])
{
    E[0][0] = scalex; E[0][1] = 0.0; E[0][2] = 0.0;
    E[1][0] = 0.0; E[1][1] = scaley; E[1][2] = 0.0;
    E[2][0] = 0.0; E[2][1] = 0.0; E[2][2] = scalez;
}

/* get scaling tensor by sampling strain field */
void straintensor(starreal x,
                  starreal y,
                  starreal z,
                  starreal E[3][3])
{
    starreal straineigval;
    starreal point[3];
    starreal scale;
    
    point[0] = x;
    point[1] = y;
    point[2] = z;
    
    straineigval = sqrt(G_evalstrain(point));
    
    if (improvebehave.verbosity > 0 && straineigval > 1.1)
    {
        printf("At point [%g %g %g], biggest eigenvalue is %g\n", x, y, z, straineigval);
    }
    
    /* scale up for stretched elements */
    scale = 1.0 / straineigval;
    if (scale > 1000.0) scale = 1000.0;
    scaletensor(scale, scale, scale, E);
}

/* blend the scaling tensor with the identity matrix */
void blendtensor(starreal E[3][3], starreal Eb[3][3])
{
    int i,j;
    
    starreal a = improvebehave.tensorblend;
    
    for (i=0; i<3; i++)
    {
        for (j=0; j<3; j++)
        {
            /* blend between tensor and tensorb */
            E[i][j] = (a * E[i][j]) + ((1.0 - a) * Eb[i][j]);
        }
    }
}

/* return the deformation tensor for the query point */
void deformtensor(starreal x, 
                  starreal y, 
                  starreal z, 
                  starreal E[3][3])
{
    starreal Eb[3][3];
    
    starreal ox, oy, oz;
    ox = x;
    oy = y;
    oz = z;
    
    /* compute the normalized vertex position */
    /* translate to the center */
    x -= G_center[0];
    y -= G_center[1];
    z -= G_center[2];
    /* scale */
    x /= G_range[0];
    y /= G_range[1];
    z /= G_range[2];
    
    switch (improvebehave.tensor)
    {
        case NOTENSOR:
            scaletensor(1.0, 1.0, 1.0, E);
            break;
        case STRETCHX:
            scaletensor(3.0, 1.0, 1.0, E);
            break;
        case STRETCHY:
            scaletensor(1.0, 3.0, 1.0, E);
            break;
        case SINK:
            sinktensor(x, y, z, E);
            break;
        case SWIRL:
            swirltensor(x, y, z, E);
            break;
        case CENTER:
            centertensor(x, y, z, E);
            break;
        case PERIMETER:
            perimetertensor(x, y, z, E);
            break;
        case RIGHT:
            righttensor(x, y, z, E);
            break;
        case SINE:
            sinetensor(x, y, z, E);
            break;
        case STRAIN:
            straintensor(ox, oy, oz, E);
            break;
        default:
            printf("Oops, don't know the tensor type %d, dying.\n", improvebehave.tensor);
            break;
    }
    
    switch (improvebehave.tensorb)
    {
        case NOTENSOR:
            scaletensor(1.0, 1.0, 1.0, Eb);
            break;
        case STRETCHX:
            scaletensor(3.0, 1.0, 1.0, Eb);
            break;
        case STRETCHY:
            scaletensor(1.0, 3.0, 1.0, Eb);
        case SINK:
            sinktensor(x, y, z, Eb);
            break;
        case SWIRL:
            swirltensor(x, y, z, Eb);
            break;
        case CENTER:
            centertensor(x, y, z, Eb);
            break;
        case PERIMETER:
            perimetertensor(x, y, z, Eb);
            break;
        case RIGHT:
            righttensor(x, y, z, Eb);
            break;
        default:
            printf("Oops, don't know the tensor type %d, dying.\n", improvebehave.tensor);
            break;
    }
    
    /* blend the tensor with the identity matrix */
    blendtensor(E, Eb);
}

/* fetch the deformation tensor sampled at the barycenter of
   the specified tetrahedron */
void tettensor(struct tetcomplex *mesh,
               tag vtx1,
               tag vtx2,
               tag vtx3,
               tag vtx4,
               starreal E[3][3])
{
    starreal *point[4];
    starreal barycenter[3] = {0.0, 0.0, 0.0};
    int i;
    
    /* get tet vertices */
    point[0] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx1))->coord;
    point[1] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx2))->coord;
    point[2] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx3))->coord;
    point[3] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx4))->coord;
    
    /* compute barycenter */
    for (i=0; i<4; i++)
    {
        vadd(point[i], barycenter, barycenter);
    }
    vscale(0.25, barycenter, barycenter);
    
    /* fetch the deformation tensor at the tet barycenter */
    deformtensor(barycenter[0], barycenter[1], barycenter[2], E);
    
    if (improvebehave.verbosity > 5)
    {
        printf("Computed deformation tensor for tet (%d %d %d %d):\n", (int) vtx1, (int) vtx2, (int) vtx3, (int) vtx4);
        printf("    v1 = (%g %g %g)\n", point[0][0], point[0][1], point[0][2]);
        printf("    v2 = (%g %g %g)\n", point[1][0], point[1][1], point[1][2]);
        printf("    v3 = (%g %g %g)\n", point[2][0], point[2][1], point[2][2]);
        printf("    v4 = (%g %g %g)\n", point[3][0], point[3][1], point[3][2]);
        printf("    barycenter = (%g %g %g)\n", barycenter[0], barycenter[1], barycenter[2]);
        printf("    E = [%g %g %g]\n", E[0][0], E[0][1], E[0][2]);
        printf("        [%g %g %g]\n", E[1][0], E[1][1], E[1][2]);
        printf("        [%g %g %g]\n", E[2][0], E[2][1], E[2][2]);
    }
}

/* fetch the deformation tensor sampled at the midpoint of the specified edge */
void edgetensor(struct tetcomplex *mesh,
               tag vtx1,
               tag vtx2,
               starreal E[3][3])
{
    starreal *point[2];
    starreal midpoint[3] = {0.0, 0.0, 0.0};
    int i;
    
    /* get edge vertices */
    point[0] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx1))->coord;
    point[1] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx2))->coord;
    
    /* compute barycenter */
    for (i=0; i<2; i++)
    {
        vadd(point[i], midpoint, midpoint);
    }
    vscale(0.5, midpoint, midpoint);
    
    /* fetch the deformation tensor at the tet barycenter */
    deformtensor(midpoint[0], midpoint[1], midpoint[2], E);
    
    if (improvebehave.verbosity > 5)
    {
        printf("Computed deformation tensor for edge (%d %d):\n", (int) vtx1, (int) vtx2);
        printf("    v1 = (%g %g %g)\n", point[0][0], point[0][1], point[0][2]);
        printf("    v2 = (%g %g %g)\n", point[1][0], point[1][1], point[1][2]);
        printf("    midpoint = (%g %g %g)\n", midpoint[0], midpoint[1], midpoint[2]);
        printf("    E = [%g %g %g]\n", E[0][0], E[0][1], E[0][2]);
        printf("        [%g %g %g]\n", E[1][0], E[1][1], E[1][2]);
        printf("        [%g %g %g]\n", E[2][0], E[2][1], E[2][2]);
    }
}

/* transform a point to isotropic space with deformation tensor E */
void tensortransform(starreal p[3], starreal pout[3], starreal E[3][3])
{
    starreal pt[3];
    
    /* copy p to temp in case p = pout */
    pt[0] = p[0];
    pt[1] = p[1];
    pt[2] = p[2];
    
    /* compute pout = Ep */
    pout[0] = (E[0][0] * pt[0]) + (E[0][1] * pt[1]) + (E[0][2] * pt[2]);
    pout[1] = (E[1][0] * pt[0]) + (E[1][1] * pt[1]) + (E[1][2] * pt[2]);
    pout[2] = (E[2][0] * pt[0]) + (E[2][1] * pt[1]) + (E[2][2] * pt[2]);
}


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineEndpointExtractor.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkCenterlineEndpointExtractor.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:46:43 $
Version:   $Revision: 1.5 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkCenterlineEndpointExtractor - Split a centerline into tracts which can be used to mark endpoints of the centerline.  
// .SECTION Description
// The methods employed here are similar to those in CenterlineBranchExtractor. Starting at (both) terminal end points of a centerline generate two, one sphere long, tracts (for four in total, two from each end of the centerline), and a single tract (n-sphere long) composed of points on the centerline connecting the "second" tracts internal endpoint (as you move the endpoint of the second tract if you moved inwards from terminal points on the centerline). The second internal tract on each side of the centerline is Blanked.

#ifndef __vtkvmtkCenterlineEndpointExtractor_h
#define __vtkvmtkCenterlineEndpointExtractor_h

#include "vtkvmtkCenterlineSplittingAndGroupingFilter.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"
  
class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineEndpointExtractor : public vtkvmtkCenterlineSplittingAndGroupingFilter
{
  public: 
  vtkTypeMacro(vtkvmtkCenterlineEndpointExtractor,vtkvmtkCenterlineSplittingAndGroupingFilter);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkCenterlineEndpointExtractor *New();

  vtkSetMacro(NumberOfEndpointSpheres,int);
  vtkGetMacro(NumberOfEndpointSpheres,int);

  vtkSetMacro(NumberOfGapSpheres,int);
  vtkGetMacro(NumberOfGapSpheres,int);

  vtkSetMacro(ExtractionMode,int);
  vtkGetMacro(ExtractionMode,int);
  void SetExtractionModeToFirstEndpoint() 
    { this->SetExtractionMode(VTK_VMTK_FIRST_ENDPOINT); }
  void SetExtractionModeToLastEndpoint() 
    { this->SetExtractionMode(VTK_VMTK_LAST_ENDPOINT); }
  void SetExtractionModeToBothEndpoints() 
    { this->SetExtractionMode(VTK_VMTK_BOTH_ENDPOINTS); }
  
  protected:
  vtkvmtkCenterlineEndpointExtractor();
  ~vtkvmtkCenterlineEndpointExtractor();  

  virtual void ComputeCenterlineSplitting(vtkPolyData* input, vtkIdType cellId) VTK_OVERRIDE;

  int NumberOfEndpointSpheres;
  int NumberOfGapSpheres;
  int ExtractionMode;

  //BTX
  enum
    {
      VTK_VMTK_FIRST_ENDPOINT,
      VTK_VMTK_LAST_ENDPOINT,
      VTK_VMTK_BOTH_ENDPOINTS
    };

  //ETX

  private:
  vtkvmtkCenterlineEndpointExtractor(const vtkvmtkCenterlineEndpointExtractor&);  // Not implemented.
  void operator=(const vtkvmtkCenterlineEndpointExtractor&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataLineEmbedder.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkPolyDataLineEmbedder.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:46:43 $
Version:   $Revision: 1.5 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataLineEmbedder.h"
#include "vtkvmtkMath.h"
#include "vtkPointData.h"
#include "vtkCellArray.h"
#include "vtkIdList.h"
#include "vtkPolygon.h"
#include "vtkTriangle.h"
#include "vtkPolyLine.h"
#include "vtkDoubleArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkPolyDataLineEmbedder);

vtkvmtkPolyDataLineEmbedder::vtkvmtkPolyDataLineEmbedder()
{
  this->Lines = NULL;
  this->EdgeArrayName = NULL;
  this->EdgePCoordArrayName = NULL;
  this->EmbeddedLinePointIds = vtkIdList::New();
  this->EmbeddedLinePointIds->Register(this);
  this->EmbeddedLinePointIds->Delete();
  this->SnapToMeshTolerance = 0.0;
}

vtkvmtkPolyDataLineEmbedder::~vtkvmtkPolyDataLineEmbedder()
{
  this->EmbeddedLinePointIds->UnRegister(this);

  if (this->Lines)
    {
    this->Lines->Delete();
    this->Lines = NULL;
    }
}

vtkIdType vtkvmtkPolyDataLineEmbedder::GetCellId(vtkPolyData* input, vtkIdList* pointIds)
{
  vtkIdType i, cellId;
  vtkIdList *cellIds, *neighborCellIds;

  cellIds = vtkIdList::New();
  neighborCellIds = vtkIdList::New();

  for (i=0; i<pointIds->GetNumberOfIds(); i++)
    {
    input->GetCellEdgeNeighbors(-1,pointIds->GetId(i),pointIds->GetId(i+1),neighborCellIds);
    if (cellIds->GetNumberOfIds()==0)
      {
      cellIds->DeepCopy(neighborCellIds);
      }
    else
      {
      cellIds->IntersectWith(*neighborCellIds);
      }
    }  

  cellId = cellIds->GetId(0);

  cellIds->Delete();
  neighborCellIds->Delete();

  return cellId;
}

void vtkvmtkPolyDataLineEmbedder::GetNeighbors(vtkIdType pointId, vtkIdList* neighborPointIds)
{
  vtkIdType i, j;
  unsigned short ncells;
  vtkIdType *cells, npts, *pts;

  this->Lines->GetPointCells(pointId,ncells,cells);

  for (i=0; i<ncells; i++)
    {
    this->Lines->GetCellPoints(cells[i],npts,pts);
    for (j=0; j<npts; j++)
      {
      if (pts[j]==pointId)
        {
        if (j>0)
          {
          neighborPointIds->InsertUniqueId(pts[j-1]);
          }
        if (j<npts-1)
          {
          neighborPointIds->InsertUniqueId(pts[j+1]);
          }
        }
      }
    }
}

void vtkvmtkPolyDataLineEmbedder::OrderNeighborhood(vtkIdList* cellPointIds, vtkIdList* neighborIds, vtkIdList* embeddedPointIds, vtkIdList* snapToMeshIds, vtkDataArray* edgeArray, vtkDataArray* edgePCoordArray, vtkIdList* orderedNeighborIds)
{
  vtkIdType j, k, h;
  vtkIdType lastCellPointIdId;
  double pCoord;
  vtkIdType edgePointIds[2];
  vtkDoubleArray* orderedNeighborPCoordArray;

  orderedNeighborPCoordArray = vtkDoubleArray::New();

  for (j=0; j<cellPointIds->GetNumberOfIds(); j++)
    {
    orderedNeighborIds->InsertNextId(cellPointIds->GetId(j));
    orderedNeighborPCoordArray->InsertNextValue(0.0);

    lastCellPointIdId = orderedNeighborIds->GetNumberOfIds()-1;

    for (k=0; k<neighborIds->GetNumberOfIds(); k++)
      {
      if (snapToMeshIds->GetId(neighborIds->GetId(k))!=-1)
        {
        continue;
        }

      edgePointIds[0] = (int)edgeArray->GetComponent(neighborIds->GetId(k),0);
      edgePointIds[1] = (int)edgeArray->GetComponent(neighborIds->GetId(k),1);

      if ((cellPointIds->GetId(j)==edgePointIds[0]) && (cellPointIds->GetId((j+1)%cellPointIds->GetNumberOfIds())==edgePointIds[1]))
        {
        pCoord = edgePCoordArray->GetComponent(neighborIds->GetId(k),0);
        }
      else if ((cellPointIds->GetId(j)==edgePointIds[1]) && (cellPointIds->GetId((j+1)%cellPointIds->GetNumberOfIds())==edgePointIds[0]))
        {
        pCoord = 1.0 - edgePCoordArray->GetComponent(neighborIds->GetId(k),0);
        }
      else 
        {
        continue;
        }

      for (h=orderedNeighborIds->GetNumberOfIds()-1; h>=lastCellPointIdId; h--)
        {
        if (pCoord<orderedNeighborPCoordArray->GetValue(h))
          {
          orderedNeighborIds->InsertId(h+1,orderedNeighborIds->GetId(h));
          orderedNeighborPCoordArray->InsertValue(h+1,orderedNeighborPCoordArray->GetValue(h));
          }
        else
          {
          orderedNeighborIds->InsertId(h+1,embeddedPointIds->GetId(neighborIds->GetId(k)));
          orderedNeighborPCoordArray->InsertValue(h+1,pCoord);
          break;
          }
        }         
      }
    }

  orderedNeighborPCoordArray->Delete();
}

void vtkvmtkPolyDataLineEmbedder::Triangulate(vtkIdList* cellPointIds, vtkIdList* orderedNeighborIds, vtkIdList* triangulationIds)
{
  vtkIdType triangleIds[3];
  vtkIdType noMove[3];
  vtkIdType numberOfNeighbors;
  bool done;

  numberOfNeighbors = orderedNeighborIds->GetNumberOfIds();

  if (numberOfNeighbors==3)
    {
    triangulationIds->InsertNextId(0);
    triangulationIds->InsertNextId(1);
    triangulationIds->InsertNextId(2);
    }

  done = false;
  
  triangleIds[0] = 0;
  while (!done)
    {
    triangleIds[1] = (triangleIds[0]+1)%numberOfNeighbors;
    triangleIds[2] = (triangleIds[0]-1+numberOfNeighbors)%numberOfNeighbors;

    if ((cellPointIds->IsId(orderedNeighborIds->GetId(triangleIds[0]))==-1)||
        (cellPointIds->IsId(orderedNeighborIds->GetId(triangleIds[1]))==-1)||
        (cellPointIds->IsId(orderedNeighborIds->GetId(triangleIds[2]))==-1))
      {
      done = true;
      break;
      }

    triangleIds[0] = triangleIds[1];
    }
  

  noMove[0] = 0;
  noMove[1] = 0;
  noMove[2] = 0;

  done = false;
  while (!done)
    {
    triangulationIds->InsertNextId(triangleIds[0]);
    triangulationIds->InsertNextId(triangleIds[1]);
    triangulationIds->InsertNextId(triangleIds[2]);

    if (cellPointIds->IsId(orderedNeighborIds->GetId(triangleIds[1]))!=-1)
      {
      triangleIds[0] = triangleIds[1];
      triangleIds[1] = (triangleIds[1]+1)%numberOfNeighbors;
      noMove[1] = 0;
      ++noMove[2];
      }
    else if (cellPointIds->IsId(orderedNeighborIds->GetId(triangleIds[2]))!=-1)
      {
      triangleIds[0] = triangleIds[2];
      triangleIds[2] = (triangleIds[2]-1+numberOfNeighbors)%numberOfNeighbors;
      ++noMove[1];
      noMove[2] = 0;
      }
    else
      {
      if (noMove[1]>noMove[2])
        {
        triangleIds[0] = triangleIds[1];
        triangleIds[1] = (triangleIds[1]+1)%numberOfNeighbors;
        noMove[1] = 0;
        ++noMove[2];
        }
      else
        {
        triangleIds[0] = triangleIds[2];
        triangleIds[2] = (triangleIds[2]-1+numberOfNeighbors)%numberOfNeighbors;
        ++noMove[1];
        noMove[2] = 0;
        }
      }

    if (triangleIds[1]==triangleIds[2])
      done = true;
    }
}

int vtkvmtkPolyDataLineEmbedder::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkIdType i, j, k;
  vtkIdType id, lineNumberOfPoints, lineNumberOfCells, cellId;
  vtkIdType inputNumberOfPoints;
  vtkIdType npts, *pts;
  vtkIdType edgePointIds0[2], edgePointIds1[2];
  double pCoord;
  vtkPoints* newPoints;
  vtkCellArray* newTriangles;
  vtkIdList* embeddedPointIds;
  vtkCellArray* addedTriangles;
  vtkIdList* cellPointIds;
  vtkIdList* newCellPointIds;
  vtkIdList* cellsToRemove;
  vtkPolygon* polygon;
  vtkCell* polyLine;
  vtkIdList* triangulationIds;
  vtkTriangle* triangle;
  vtkIdList* neighborIds;
  vtkIdList* orderedNeighborIds;
  vtkIdList* lineConnectedNeighbors;
  vtkIdList* snapToMeshIds;
  vtkDataArray* edgeArray;
  vtkDataArray* edgePCoordArray;
  double triangleArea, weights[3];

  vtkPointData *inputPD = input->GetPointData();
  vtkPointData *outputPD = output->GetPointData();

  if (this->Lines->GetNumberOfPoints()==0)
    {
    vtkWarningMacro(<<"Line to embed has no points.");
    return 1;
    }

  if (this->EdgeArrayName==NULL)
    {
    vtkErrorMacro(<<"Edge array name not specified.");
    return 1;
    }

  if (this->EdgePCoordArrayName==NULL)
    {
    vtkErrorMacro(<<"EdgePCoord array name not specified.");
    return 1;
    }

  edgeArray = this->Lines->GetPointData()->GetArray(this->EdgeArrayName);

  if (edgeArray==NULL)
    {
    vtkErrorMacro(<<"Edge array with name specified does not exist.");
    return 1;
    }

  edgePCoordArray = this->Lines->GetPointData()->GetArray(this->EdgePCoordArrayName);

  if (edgePCoordArray==NULL)
    {
    vtkErrorMacro(<<"EdgePCoord array with name specified does not exist.");
    return 1;
    }

  newPoints = vtkPoints::New();
  newTriangles = vtkCellArray::New();
  embeddedPointIds = vtkIdList::New();
  addedTriangles = vtkCellArray::New();
  cellPointIds = vtkIdList::New();
  newCellPointIds = vtkIdList::New();
  cellsToRemove = vtkIdList::New();
  polygon = vtkPolygon::New();
  triangulationIds = vtkIdList::New();
  neighborIds = vtkIdList::New();
  orderedNeighborIds = vtkIdList::New();
  lineConnectedNeighbors = vtkIdList::New();
  snapToMeshIds = vtkIdList::New();

  newPoints->DeepCopy(input->GetPoints());

  input->BuildCells();
  input->BuildLinks();

  this->Lines->BuildCells();
  this->Lines->BuildLinks();
  
  inputNumberOfPoints = input->GetNumberOfPoints();
    
  lineNumberOfPoints = this->Lines->GetNumberOfPoints();
  lineNumberOfCells = this->Lines->GetNumberOfCells();

  outputPD->InterpolateAllocate(inputPD,inputNumberOfPoints+lineNumberOfPoints);

  for (i=0; i<inputNumberOfPoints; i++)
    {
    outputPD->CopyData(inputPD,i,i);
    }

  snapToMeshIds->SetNumberOfIds(lineNumberOfPoints);
  embeddedPointIds->SetNumberOfIds(lineNumberOfPoints);

  for (i=0; i<lineNumberOfPoints; i++)
    {
    edgePointIds0[0] = static_cast<vtkIdType>(edgeArray->GetComponent(i,0));
    edgePointIds0[1] = static_cast<vtkIdType>(edgeArray->GetComponent(i,1));
    pCoord = edgePCoordArray->GetComponent(i,0);

    if (this->SnapToMeshTolerance>0.0)
      {
      if (edgePointIds0[0] == -1)
        {
        snapToMeshIds->SetId(i,-1);
        }
      else
        {
        if (pCoord < this->SnapToMeshTolerance)
          {
          snapToMeshIds->SetId(i,edgePointIds0[0]);
          }
        else if (pCoord > 1.0-this->SnapToMeshTolerance)
          {
          snapToMeshIds->SetId(i,edgePointIds0[1]);
          }
        else
          {
          snapToMeshIds->SetId(i,-1);
          }
        }
      }
    else
      {
      snapToMeshIds->SetId(i,-1);
      }

    if (snapToMeshIds->GetId(i)==-1)
      {
      id = newPoints->InsertNextPoint(this->Lines->GetPoint(i));
      if (edgePointIds0[0] != -1)
        {
        outputPD->InterpolateEdge(inputPD,id,edgePointIds0[0],edgePointIds0[1],pCoord);
        }
      }
    else
      {
      id = snapToMeshIds->GetId(i);
      }
    
    embeddedPointIds->SetId(i,id);
    }

  for (k=0; k<lineNumberOfCells; k++)
    {
    polyLine = this->Lines->GetCell(k);
    if (polyLine->GetCellType() != VTK_LINE && polyLine->GetCellType() != VTK_POLY_LINE)
      {
      continue;
      }

    for (i=1; i<polyLine->GetNumberOfPoints(); i++)
      {
      edgePointIds0[0] = static_cast<vtkIdType>(edgeArray->GetComponent(polyLine->GetPointId(i-1),0));
      edgePointIds0[1] = static_cast<vtkIdType>(edgeArray->GetComponent(polyLine->GetPointId(i-1),1));
      edgePointIds1[0] = static_cast<vtkIdType>(edgeArray->GetComponent(polyLine->GetPointId(i),0));
      edgePointIds1[1] = static_cast<vtkIdType>(edgeArray->GetComponent(polyLine->GetPointId(i),1));

      if ((snapToMeshIds->GetId(polyLine->GetPointId(i-1))!=-1)&&(snapToMeshIds->GetId(polyLine->GetPointId(i))!=-1))
        {
        continue;
        }

      if ((edgePointIds0[0]==-1)||(edgePointIds1[0]==-1))
        {
        continue;
        }

      cellPointIds->Initialize();
      cellPointIds->InsertNextId(edgePointIds0[0]);
      cellPointIds->InsertUniqueId(edgePointIds0[1]);
      cellPointIds->InsertUniqueId(edgePointIds1[0]);
      cellPointIds->InsertUniqueId(edgePointIds1[1]);

      cellId = this->GetCellId(input,cellPointIds);

      cellsToRemove->InsertUniqueId(cellId);
      }
    }

  for (i=0; i<cellsToRemove->GetNumberOfIds(); i++)
    {
    cellId = cellsToRemove->GetId(i);
    cellPointIds->Initialize();
    input->GetCellPoints(cellId,cellPointIds);

    neighborIds->Initialize();

    for (k=0; k<lineNumberOfPoints; k++)
      {
      edgePointIds0[0] = static_cast<vtkIdType>(edgeArray->GetComponent(k,0));
      edgePointIds0[1] = static_cast<vtkIdType>(edgeArray->GetComponent(k,1));
        
      for (j=0; j<cellPointIds->GetNumberOfIds(); j++)
        {
        if (((cellPointIds->GetId(j)==edgePointIds0[0])&&(cellPointIds->GetId((j+1)%cellPointIds->GetNumberOfIds())==edgePointIds0[1]))||
            ((cellPointIds->GetId(j)==edgePointIds0[1])&&(cellPointIds->GetId((j+1)%cellPointIds->GetNumberOfIds())==edgePointIds0[0])))
          {
          neighborIds->InsertNextId(k);
          break;
          }
        }
      }

    orderedNeighborIds->Initialize();
    this->OrderNeighborhood(cellPointIds,neighborIds,embeddedPointIds,snapToMeshIds,edgeArray,edgePCoordArray,orderedNeighborIds);

    triangulationIds->Initialize();
    this->Triangulate(cellPointIds,orderedNeighborIds,triangulationIds);

    for (j=0; j<triangulationIds->GetNumberOfIds(); j+=3)
      {
      addedTriangles->InsertNextCell(3);
      addedTriangles->InsertCellPoint(orderedNeighborIds->GetId(triangulationIds->GetId(j)));
      addedTriangles->InsertCellPoint(orderedNeighborIds->GetId(triangulationIds->GetId(j+1)));
      addedTriangles->InsertCellPoint(orderedNeighborIds->GetId(triangulationIds->GetId(j+2)));
      }
    }

  for (i=0; i<lineNumberOfPoints; i++)
    {
    edgePointIds0[0] = static_cast<vtkIdType>(edgeArray->GetComponent(i,0));

    if (edgePointIds0[0]!=-1)
      {
      continue;
      }

    neighborIds->Initialize();
    this->GetNeighbors(i,neighborIds);

    cellPointIds->Initialize();
    for (j=0; j<neighborIds->GetNumberOfIds(); j++)
      {
      edgePointIds1[0] = static_cast<vtkIdType>(edgeArray->GetComponent(neighborIds->GetId(j),0));
      edgePointIds1[1] = static_cast<vtkIdType>(edgeArray->GetComponent(neighborIds->GetId(j),1));
      cellPointIds->InsertUniqueId(edgePointIds1[0]);
      cellPointIds->InsertUniqueId(edgePointIds1[1]);
      }

    cellId = this->GetCellId(input,cellPointIds);

    cellsToRemove->InsertUniqueId(cellId);

    cellPointIds->Initialize();
    input->GetCellPoints(cellId,cellPointIds);

    orderedNeighborIds->Initialize();
    this->OrderNeighborhood(cellPointIds,neighborIds,embeddedPointIds,snapToMeshIds,edgeArray,edgePCoordArray,orderedNeighborIds);

    for (j=0; j<orderedNeighborIds->GetNumberOfIds(); j++)
      {
      addedTriangles->InsertNextCell(3);
      addedTriangles->InsertCellPoint(embeddedPointIds->GetId(i));
      addedTriangles->InsertCellPoint(orderedNeighborIds->GetId(j));
      addedTriangles->InsertCellPoint(orderedNeighborIds->GetId((j+1)%orderedNeighborIds->GetNumberOfIds()));
      }

    double newPoint0[3], newPoint1[3], newPoint2[3], embeddedPoint[3];
    newPoints->GetPoint(cellPointIds->GetId(0),newPoint0);
    newPoints->GetPoint(cellPointIds->GetId(1),newPoint1);
    newPoints->GetPoint(cellPointIds->GetId(2),newPoint2);
    newPoints->GetPoint(embeddedPointIds->GetId(i),embeddedPoint);

    triangleArea = vtkvmtkMath::TriangleArea(newPoint0,newPoint1,newPoint1);
    weights[0] = vtkvmtkMath::TriangleArea(embeddedPoint,newPoint1,newPoint2) / triangleArea;
    weights[1] = vtkvmtkMath::TriangleArea(newPoint0,embeddedPoint,newPoint2) / triangleArea;
    weights[2] = vtkvmtkMath::TriangleArea(newPoint0,newPoint1,embeddedPoint) / triangleArea;

    outputPD->InterpolatePoint(inputPD,embeddedPointIds->GetId(i),cellPointIds,weights);

    }

  for (addedTriangles->InitTraversal(); addedTriangles->GetNextCell(npts,pts); )
    {
    newTriangles->InsertNextCell(npts,pts);
    }

  for (i=0; i<input->GetNumberOfCells(); i++)
    {
    triangle = vtkTriangle::SafeDownCast(input->GetCell(i));
    if (triangle==NULL)
      {
      continue;
      }
    if (cellsToRemove->IsId(i)==-1)
      {
      newTriangles->InsertNextCell(triangle);
      }
    }
  
  output->SetPoints(newPoints);
  output->SetPolys(newTriangles);

  this->EmbeddedLinePointIds->DeepCopy(embeddedPointIds);

  newPoints->Delete();
  newTriangles->Delete();
  embeddedPointIds->Delete();
  addedTriangles->Delete();
  cellPointIds->Delete();
  newCellPointIds->Delete();
  cellsToRemove->Delete();
  polygon->Delete();
  triangulationIds->Delete();
  neighborIds->Delete();
  orderedNeighborIds->Delete();
  lineConnectedNeighbors->Delete();
  snapToMeshIds->Delete();

  return 1;
}

void vtkvmtkPolyDataLineEmbedder::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


<|start_filename|>vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITK.h<|end_filename|>
/*=========================================================================

  Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.

  See Doc/copyright/copyright.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  Program:   vtkvmtkITK
  Module:    $HeadURL: http://www.na-mic.org/svn/Slicer3/trunk/Libs/vtkITK/vtkITK.h $
  Date:      $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $
  Version:   $Revision: 1900 $

==========================================================================*/
//
// use an ifdef on SLICER_VTK5 to flag code that won't
// compile on vtk4.4 and before
//
//#if ( (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION >= 5 ) )
//#define SLICER_VTK5
//#endif

#include "vtkvmtkWin32Header.h"


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineBranchGeometry.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkCenterlineBranchGeometry.h,v $
Language:  C++
Date:      $Date: 2006/07/17 09:52:56 $
Version:   $Revision: 1.8 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkCenterlineBranchGeometry - Computes the length, curvature, torsion, and tortuosity each for branch within a split centerline. 
// .SECTION Description
// The length, curvature, torsion, and tortuosity metrics are scalar quantities which are identical for each point / tract that makes up a branch. They are cell data which are attached to all cells in the branch.
//
// A laplacian smoothing filter can be applied to the line if the computation appears to be unstable (as we are using second derivatives and such here). 

#ifndef __vtkvmtkCenterlineBranchGeometry_h
#define __vtkvmtkCenterlineBranchGeometry_h

#include "vtkPolyDataAlgorithm.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"
#include "vtkPolyData.h"

class vtkPoints;
class vtkDoubleArray;
class vtkIntArray;
  
class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineBranchGeometry : public vtkPolyDataAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkCenterlineBranchGeometry,vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkCenterlineBranchGeometry* New();

  vtkSetStringMacro(RadiusArrayName);
  vtkGetStringMacro(RadiusArrayName);

  vtkSetStringMacro(GroupIdsArrayName);
  vtkGetStringMacro(GroupIdsArrayName);

  vtkSetStringMacro(BlankingArrayName);
  vtkGetStringMacro(BlankingArrayName);

  vtkSetStringMacro(LengthArrayName);
  vtkGetStringMacro(LengthArrayName);

  vtkSetStringMacro(CurvatureArrayName);
  vtkGetStringMacro(CurvatureArrayName);

  vtkSetStringMacro(TorsionArrayName);
  vtkGetStringMacro(TorsionArrayName);

  vtkSetStringMacro(TortuosityArrayName);
  vtkGetStringMacro(TortuosityArrayName);

  vtkSetMacro(MinSubsamplingSpacing,double);
  vtkGetMacro(MinSubsamplingSpacing,double);

  vtkSetMacro(SmoothingFactor,double);
  vtkGetMacro(SmoothingFactor,double);

  vtkSetMacro(NumberOfSmoothingIterations,int);
  vtkGetMacro(NumberOfSmoothingIterations,int);

  vtkSetMacro(LineSmoothing,int);
  vtkGetMacro(LineSmoothing,int);
  vtkBooleanMacro(LineSmoothing,int);

  vtkSetMacro(LineSubsampling,int);
  vtkGetMacro(LineSubsampling,int);
  vtkBooleanMacro(LineSubsampling,int);

  vtkSetMacro(SphereSubsampling,int);
  vtkGetMacro(SphereSubsampling,int);
  vtkBooleanMacro(SphereSubsampling,int);

  protected:
  vtkvmtkCenterlineBranchGeometry();
  ~vtkvmtkCenterlineBranchGeometry();  

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  double ComputeGroupLength(vtkPolyData* input, int branchGroupId);
  double ComputeGroupCurvature(vtkPolyData* input, int branchGroupId);
  double ComputeGroupTorsion(vtkPolyData* input, int branchGroupId);
  double ComputeGroupTortuosity(vtkPolyData* input, int branchGroupId, double groupLength);

  static void SubsampleLine(vtkPoints* linePoints, vtkPoints* subsampledLinePoints, double minSpacing = 0.01);
  void SphereSubsampleLine(vtkPolyData* input, vtkIdType cellId, vtkPoints* subsampledLinePoints);

  char* RadiusArrayName;
  char* GroupIdsArrayName;
  char* BlankingArrayName;

  char* LengthArrayName;
  char* CurvatureArrayName;
  char* TorsionArrayName;
  char* TortuosityArrayName;

  int LineSubsampling;
  int SphereSubsampling;
  int LineSmoothing;

  double MinSubsamplingSpacing;
  double SmoothingFactor;
  int NumberOfSmoothingIterations;

  private:
  vtkvmtkCenterlineBranchGeometry(const vtkvmtkCenterlineBranchGeometry&);  // Not implemented.
  void operator=(const vtkvmtkCenterlineBranchGeometry&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/Starbase.h<|end_filename|>
/* This file was automatically generated.  Do not edit! */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stddef.h>
#include <string.h>
#include <math.h>
#if !defined(NO_TIMER)
#include <sys/time.h>
#endif
#if defined(CPU86)
#include <float.h>
#endif
#if defined(LINUX)
#include <fpu_control.h>
#endif
#if !defined(NOMAIN)
int main(int argc,char **argv);
#endif
typedef struct behavior behavior;
typedef struct inputs inputs;
typedef struct outputs outputs;
typedef struct tetcomplex tetcomplex;
void statistics(struct behavior *behave,struct inputs *in,struct outputs *out,struct tetcomplex *plex);
void statisticsquality(struct behavior *behave,struct tetcomplex *plex);
typedef size_t starulong;
typedef starulong arraypoolulong;
void outputfaces(struct behavior *behave,struct inputs *in,struct tetcomplex *plex,arraypoolulong facecount,int argc,char **argv);
void outputedges(struct behavior *behave,struct inputs *in,struct tetcomplex *plex,arraypoolulong edgecount,int argc,char **argv);
void outputtetrahedra(struct behavior *behave,struct inputs *in,struct tetcomplex *plex,int argc,char **argv);
typedef struct proxipool proxipool;
void outputnumbervertices(struct behavior *behave,struct inputs *in,struct proxipool *pool);
void outputvertices(struct behavior *behave,struct inputs *in,struct proxipool *pool,arraypoolulong vertexcount,int argc,char **argv);
void outputpreparevertices(struct behavior *behave,struct tetcomplex *plex);
#if !defined(STARLIBRARY)
void outputfilefinish(FILE *outfile,int argc,char **argv);
#endif
typedef struct segment segment;
struct segment *inputsegments(struct behavior *behave,struct inputs *in,FILE *polyfile);
void inputsegment(struct behavior *behave,struct inputs *in,FILE *polyfile,arraypoolulong segnumber,int markflag,struct segment *seg);
int inputsegmentheader(struct behavior *behave,struct inputs *in,FILE *polyfile);
void inputtetrahedra(struct behavior *behave,struct inputs *in,struct proxipool *vertexpool,struct outputs *out,struct tetcomplex *plex);
typedef arraypoolulong tag;
void inputmaketagmap(struct proxipool *vertexpool,arraypoolulong firstnumber,tag *vertextags);
FILE *inputverticesreadsortstore(struct behavior *behave,struct inputs *in,struct proxipool *pool);
void inputverticessortstore(char *vertices,struct inputs *in,struct proxipool *pool);
void inputverticesintopool2(char *vertices,struct inputs *in,struct proxipool *pool);
void inputverticesintopool(char *vertices,struct inputs *in,struct proxipool *pool);
void inputvertexsort2(char *vertices,tag *vertextags,arraypoolulong vertexcount,size_t vertexbytes,unsigned int attribcount);
void inputvertexsort(char *vertices,tag *vertextags,arraypoolulong vertexcount,size_t vertexbytes,unsigned int attribcount);
char *inputvertexfile(struct behavior *behave,struct inputs *in,FILE **polyfile);
#if !defined(STARLIBRARY)
char *inputvertices(FILE *vertexfile,char *vertexfilename,struct inputs *in,int markflag);
char *inputfindfield(char *string);
char *inputtextline(char *string,FILE *infile,char *infilename);
#endif
int vertexcheckdelaunay(struct behavior *behave,struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag adjacencies[2]);
void vertexcheckpointintet(struct behavior *behave,struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4,tag invertex);
void vertexcheckorientation(struct behavior *behave,struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4);
struct outputs {
  arraypoolulong vertexcount;
  arraypoolulong tetcount;
  arraypoolulong facecount;
  arraypoolulong boundaryfacecount;
  arraypoolulong edgecount;
};
struct inputs {
  tag *vertextags;
  arraypoolulong vertexcount;                   /* Number of input vertices. */
  unsigned int attribcount;              /* Number of attributes per vertex. */
  arraypoolulong firstnumber;   /* Vertices are numbered starting from this. */
  arraypoolulong deadvertexcount;     /* Non-corner input vertices (killed). */
  arraypoolulong tetcount;                    /* Number of input tetrahedra. */
  unsigned int tetattribcount;      /* Number of attributes per tetrahedron. */
  arraypoolulong segmentcount;                  /* Number of input segments. */
  arraypoolulong facetcount;                      /* Number of input facets. */
  arraypoolulong holecount;                        /* Number of input holes. */
  arraypoolulong regioncount;                    /* Number of input regions. */
};
typedef struct facet facet;
typedef int vertexmarktype;
struct facet {
  vertexmarktype mark;
  arraypoolulong number;
};
struct segment {
  tag endpoint[2];
  struct segment *nextsegment[2];
  vertexmarktype mark;
  short acute[2];
  arraypoolulong number;
};
typedef struct vertexshort vertexshort;
typedef double starreal;
#if defined(SINGLE)
typedef float starreal;
#endif
struct vertexshort {
  vertexmarktype mark;
  starreal coord[3];
};
typedef struct vertex vertex;
struct vertex {
  starreal coord[3];
  vertexmarktype mark;
  arraypoolulong number;
};
#define ACTIVEVERTEX ((arraypoolulong) ~1)
#define DEADVERTEX ((arraypoolulong) ~0)
arraypoolulong tetcomplexbytes(struct tetcomplex *plex);
arraypoolulong tetcomplexghosttetcount(struct tetcomplex *plex);
arraypoolulong tetcomplextetcount(struct tetcomplex *plex);
void tetcomplexremoveghosttets(struct tetcomplex *plex);
typedef struct arraypool arraypool;
void tetcomplexbuild3dstar(struct tetcomplex *plex,tag newvertex,struct arraypool *trianglelist,arraypoolulong firstindex,arraypoolulong trianglecount);
void tetcomplex41flip(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4,tag deletevertex);
void tetcomplex32flip(struct tetcomplex *plex,tag vtxtop,tag vtx1,tag vtx2,tag vtx3,tag vtxbot);
void tetcomplex23flip(struct tetcomplex *plex,tag vtxtop,tag vtx1,tag vtx2,tag vtx3,tag vtxbot);
void tetcomplex14flip(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4,tag newvertex);
void tetcomplex12flipon6edges(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4,tag newvertex);
void tetcomplex12flipon3edges(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4,tag newvertex);
void tetcomplexsqueezetriangle(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3);
void tetcomplexsqueezeonedge(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3);
void tetcomplexsqueezeonhalfedge(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3);
void tetcomplexdeletetriangle(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3);
void tetcomplex21fliponedge(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3);
int tetcomplexinserttetontripod(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4);
void tetcomplex12fliponedge(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4,tag newvertex);
int tetcomplexinserttet(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4);
int tetcomplexinsertorderedtet(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4);
typedef struct tetcomplexstar tetcomplexstar;
struct tetcomplexstar *tetcomplexlookup3dstar(struct tetcomplex *plex,tag vtx);
int tetcomplexdeletetet(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4);
int tetcomplexdeleteorderedtet(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4);
void tetcomplexconsistency(struct tetcomplex *plex);
unsigned int tetcomplexmissingtet(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag vtx4);
void tetcomplexprintstars(struct tetcomplex *plex);
void tetcomplexprint(struct tetcomplex *plex);
typedef struct tetcomplexposition tetcomplexposition;
void tetcomplexiteratenoghosts(struct tetcomplexposition *pos,tag nexttet[4]);
void tetcomplexiterate(struct tetcomplexposition *pos,tag nexttet[4]);
void tetcomplexiterateall(struct tetcomplexposition *pos,tag nexttet[4]);
void tetcomplexiteratorinit(struct tetcomplex *plex,struct tetcomplexposition *pos);
int tetcomplexvertex2tet(struct tetcomplex *plex,tag vtx,tag adjtet[4]);
int tetcomplexedge2tet(struct tetcomplex *plex,tag vtx1,tag vtx2,tag adjtet[4]);
int tetcomplexadjacencies(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag adjacencies[2]);
int tetcomplexringadjacencies(struct tetcomplex *plex,tag vtx1,tag vtx2,tag vtx3,tag adjacencies[2]);
typedef struct minipoolheader minipoolheader;
#define arraypoolfastlookup(pool, index)  \
  (void *) ((pool)->toparray[(index) >> (pool)->log2objectsperblock] +  \
            ((index) & ((pool)->objectsperblock - 1)) * (pool)->objectbytes)
#define LOG2OBJECTSPERMINI 10
#define proxipooltag2mini(pool, searchtag)  \
  ((struct minipoolheader *)  \
   arraypoolfastlookup(&(pool)->minipoolarray,  \
                       (searchtag) >> LOG2OBJECTSPERMINI))
#define OBJECTSPERMINI 1024
#define proxipooltag2object2(pool, searchtag)  \
  ((void *) (proxipooltag2mini(pool, searchtag)->object2block +  \
             (searchtag & (tag) (OBJECTSPERMINI - 1)) * (pool)->objectbytes2))
#define tetcomplextag2attributes(plex, searchtag)  \
  proxipooltag2object2(plex->vertexpool, searchtag)
#define proxipooltag2object(pool, searchtag)  \
  ((void *) (proxipooltag2mini(pool, searchtag)->object1block +  \
             (searchtag & (OBJECTSPERMINI - 1)) * (pool)->objectbytes1))
#define tetcomplextag2vertex(plex, searchtag)  \
  proxipooltag2object(plex->vertexpool, searchtag)
void tetcomplexdeinit(struct tetcomplex *plex);
void tetcomplexrestart(struct tetcomplex *plex);
void tetcomplexinit(struct tetcomplex *plex,struct proxipool *vertexpool,int verbose);
typedef struct tetcomplexlinktriangle tetcomplexlinktriangle;
struct tetcomplexlinktriangle {
  tag vtx[3];
  arraypoolulong neighbor[3];
};
typedef struct link2dposition link2dposition;
typedef struct linkposition linkposition;
typedef char *molecule;
struct linkposition {
  molecule cule;      /* The molecule containing the atom (or right before). */
  int textindex;                                   /* The index of the atom. */
  int lasttextindex;   /* The last atom not part of the "next molecule" tag. */
  tag moleculetag;                       /* The tag for the molecule `cule'. */
  tag nextmoleculetag;  /* The next tag following `moleculetag' in the list. */
  tag groundtag;            /* Tag for the link's owner, used to decompress. */
  struct proxipool *pool;  /* The pool in which the molecules are allocated. */
};
struct link2dposition {
  struct linkposition innerpos;                  /* Position in the 2D link. */
  tag linktag;     /* Tag for the link's first molecule, used to decompress. */
};
struct tetcomplexposition {
  struct tetcomplex *mycomplex;          /* The complex this position is in. */
  tag starvertex;     /* The vertex whose star is currently being traversed. */
  struct link2dposition link2dposition;            /* That vertex's 2D link. */
  tag link2dvertex;                  /* Vertex in 2D link, denoting an edge. */
  struct linkposition link1dposition;           /* That edge's 1D link ring. */
  tag link1dfirstvertex;    /* First vertex in ring (needed at end of ring). */
  tag link1dprevvertex;                 /* Vertex visited on last iteration. */
};
struct tetcomplexstar {
  tag linkhead;                 /* First molecule of the link2d linked list. */
  tag linktail;                  /* Last molecule of the link2d linked list. */
};
struct arraypool {
  arraypoolulong objectbytes;       /* Size of one object in the lower tier. */
  arraypoolulong objectsperblock;           /* Objects per lower tier block. */
  arraypoolulong log2objectsperblock;      /* Base-2 logarithm of the above. */
  arraypoolulong totalmemory;     /* Total bytes used by whole tiered array. */
  arraypoolulong objects;          /* Number of currently allocated objects. */

  char **toparray;                             /* Pointer to the upper tier. */
  arraypoolulong toparraylen;      /* Length of the upper tier, in pointers. */
  arraypoolulong firstvirgin;          /* First never-allocated array index. */
  arraypoolulong deadindexstack;        /* Stack of freed objects, by index. */
  void *deadobjectstack;              /* Stack of freed objects, by pointer. */
};
typedef arraypoolulong proxipoolulong;
struct proxipool {
  size_t objectbytes1;                    /* Size of one object in the pool. */
  size_t objectbytes2;                      /* Size of supplementary object. */
  size_t block1offset;                /* Offset of first object from header. */
  size_t block2offset;              /* Offset of first supplementary object. */
  size_t minipoolsize;            /* Size of one minipool, including header. */

  struct arraypool minipoolarray;              /* Tiered array of minipools. */
  arraypoolulong objects;          /* Number of currently allocated objects. */
  arraypoolulong maxobjects;              /* Maximum allocated objects ever. */
  tag nextgroup;                 /* Next group of minipools to be allocated. */

  struct arraypool poolpools;                  /* Tiered array of poolpools. */
  proxipoolulong nextinitindex;   /* First uninitialized index in the array. */
  int verbosity;                /* Amount of debugging information to print. */
};
#define LINK2DCACHESIZE 16384
typedef struct {
  tag mylink2d;
  tag myvertex;
  tag mylinkring;
}link2dcache[LINK2DCACHESIZE];
struct tetcomplex {
  struct proxipool moleculepool;     /* Pool of molecules storing the links. */
  struct arraypool stars;    /* `tetcomplexstar' array addressing the links. */
  struct proxipool *vertexpool;                     /* The pool of vertices. */
  tag nextinitindex;      /* First uninitialized index in the `stars' array. */
  arraypoolulong tetcount;           /* Number of tetrahedra in the complex. */
  arraypoolulong ghosttetcount;          /* Ghost tetrahedra in the complex. */
  int consistentflag;           /* Are the stars consistent with each other? */
  int verbosity;                /* Amount of debugging information to print. */
  link2dcache cache;                  /* Cache for fast lookups in 2D links. */
};
void tricircumcenter3d(struct behavior *b,starreal *triorg,starreal *tridest,starreal *triapex,starreal *circumcenter,starreal *normal,starreal *xi,starreal *eta);
void tetcircumcenter(struct behavior *b,starreal *tetorg,starreal *tetdest,starreal *tetfapex,starreal *tettapex,starreal *circumcenter,starreal *xi,starreal *eta,starreal *zeta);
starreal nonregular(struct behavior *b,starreal *pa,starreal *pb,starreal *pc,starreal *pd,starreal *pe);
starreal orient4d(struct behavior *b,starreal *pa,starreal *pb,starreal *pc,starreal *pd,starreal *pe,starreal aheight,starreal bheight,starreal cheight,starreal dheight,starreal eheight);
starreal orient4dadapt(starreal *pa,starreal *pb,starreal *pc,starreal *pd,starreal *pe,starreal aheight,starreal bheight,starreal cheight,starreal dheight,starreal eheight,starreal permanent);
starreal orient4dexact(starreal *pa,starreal *pb,starreal *pc,starreal *pd,starreal *pe,starreal aheight,starreal bheight,starreal cheight,starreal dheight,starreal eheight);
starreal insphere(struct behavior *b,starreal *pa,starreal *pb,starreal *pc,starreal *pd,starreal *pe);
starreal insphereadapt(starreal *pa,starreal *pb,starreal *pc,starreal *pd,starreal *pe,starreal permanent);
starreal insphereexact(starreal *pa,starreal *pb,starreal *pc,starreal *pd,starreal *pe);
starreal orient3d(struct behavior *b,starreal *pa,starreal *pb,starreal *pc,starreal *pd);
starreal orient3dadapt(starreal *pa,starreal *pb,starreal *pc,starreal *pd,starreal permanent);
starreal orient2d(struct behavior *b,starreal ax,starreal ay,starreal bx,starreal by,starreal cx,starreal cy);
starreal orient2dadapt(starreal ax,starreal ay,starreal bx,starreal by,starreal cx,starreal cy,starreal detsum);
starreal estimate(int elen,starreal *e);
int scale_expansion_zeroelim(int elen,starreal *e,starreal b,starreal *h);
int fast_expansion_sum_zeroelim(int elen,starreal *e,int flen,starreal *f,starreal *h);
void primitivesinit(void);
tag link2ddeletevertex(struct proxipool *pool,link2dcache cache,tag linkhead,tag *linktail,tag groundtag,tag deletevertex);
tag link2ddeletevertexnocache(struct proxipool *pool,tag linkhead,tag *linktail,tag groundtag,tag deletevertex);
tag link2dfindinsert(struct proxipool *pool,link2dcache cache,tag linkhead,tag *linktail,tag groundtag,tag searchvertex);
void link2dinsertvertex(struct proxipool *pool,link2dcache cache,tag linkhead,tag *linktail,tag groundtag,tag newvertex,tag linkring);
void link2dinsertvertexnocache(struct proxipool *pool,tag linkhead,tag *linktail,tag groundtag,tag newvertex,tag linkring);
tag link2dfindring(struct proxipool *pool,link2dcache cache,tag link,tag groundtag,tag searchvertex);
tag link2dfindringnocache(struct proxipool *pool,tag link,tag groundtag,tag searchvertex,tag *linktail);
void link2dcacheinit(link2dcache cache);
void link2dprint(struct proxipool *pool,tag link,tag groundtag);
void link2diterate(struct link2dposition *pos,tag vertexandlink[2]);
void link2diteratorinit(struct proxipool *pool,tag link,tag groundtag,struct link2dposition *pos);
int link2disempty(struct proxipool *pool,tag link);
void link2ddelete(struct proxipool *pool,tag link);
tag link2dnew(struct proxipool *pool,proxipoolulong allocindex);
#define LINK2DPRIME 16908799u
int linkringdelete2vertices(struct proxipool *pool,tag linkring,tag groundtag,tag deletevertex);
int linkringdeletevertex(struct proxipool *pool,tag linkring,tag groundtag,tag deletevertex);
int linkringinsertvertex(struct proxipool *pool,tag linkring,tag groundtag,tag searchvertex,tag newvertex);
int linkringdeleteedge(struct proxipool *pool,tag linkring,tag groundtag,tag endpoint1,tag endpoint2);
int linkringinsertedge(struct proxipool *pool,tag linkring,tag groundtag,tag endpoint1,tag endpoint2);
typedef struct linkpossmall linkpossmall;
void linkringrotateatoms(struct proxipool *pool,tag linkring,struct linkpossmall *pos1,struct linkpossmall *pos2,struct linkpossmall *pos3);
tag linkringdeleteatoms(struct proxipool *pool,struct linkpossmall *deleteposition,int numatoms);
tag linkringdeleteatoms2(struct proxipool *pool,struct linkpossmall *deleteposition,int numatoms);
tag linkringinsertatoms(struct proxipool *pool,struct linkpossmall *insertposition,int numatoms,char *newatombuffer,proxipoolulong allocindex);
tag linkringinsertatoms2(struct proxipool *pool,struct linkpossmall *insertposition,int numatoms,char *newatombuffer,proxipoolulong allocindex);
void linkringprint(struct proxipool *pool,tag linkring,tag groundtag);
tag linkringiterate(struct linkposition *pos);
void linkringiteratorinit(struct proxipool *pool,tag linkring,tag groundtag,struct linkposition *pos);
int linkringadjacencies(struct proxipool *pool,tag linkring,tag groundtag,tag searchvertex,tag adjacencies[2]);
int linkringadjacencies2(struct proxipool *pool,tag linkring,tag groundtag,tag searchvertex,tag adjacencies[2]);
void linkringdelete(struct proxipool *pool,tag linkring);
void linkringrestart(struct proxipool *pool,tag linkring);
#define MOLECULESIZE 20
#define STOP (~ (tag) 1)
void internalerror(void);
#define linkringreadtag(moleculetag, cule, atomindex, nextmoleculetag,  \
                        nowatom, errstring)  \
  nowatom = cule[MOLECULESIZE - 1];  \
  atomindex = MOLECULESIZE - 2;  \
  if (nowatom == (char) STOP) {  \
    nextmoleculetag = STOP;  \
  } else {  \
    nextmoleculetag = nowatom & (char) 127;  \
    while (nowatom >= (char) 0) {  \
      if (atomindex < 0) {  \
        printf(errstring);  \
        printf("  Tag for next molecule not properly terminated.\n");  \
        internalerror();  \
      }  \
      nowatom = cule[atomindex];  \
      nextmoleculetag = (nextmoleculetag << 7) + (nowatom & (char) 127);  \
      atomindex--;  \
    }  \
    nextmoleculetag += (moleculetag >>  \
                        (7 * (MOLECULESIZE - 1 - atomindex))) <<  \
                       (7 * (MOLECULESIZE - 1 - atomindex));  \
  }
tag linkringnewfill(struct proxipool *pool,tag groundtag,tag *tagarray,proxipoolulong tagarraylen,proxipoolulong allocindex);
tag linkringnew(struct proxipool *pool,proxipoolulong allocindex);
int linkringtagcompress(tag groundtag,tag newtag,char *newtagatoms);
struct linkpossmall {
  molecule cule;      /* The molecule containing the atom (or right before). */
  int textindex;                                   /* The index of the atom. */
  int lasttextindex;   /* The last atom not part of the "next molecule" tag. */
  tag moleculetag;                       /* The tag for the molecule `cule'. */
  tag nextmoleculetag;  /* The next tag following `moleculetag' in the list. */
};
#define COMPRESSEDTAGLENGTH (8 * sizeof(tag) / 7 + 2)
#define MOLECULEQUEUESIZE 40
#define GHOSTVERTEX (~ (tag) 0)
typedef struct allocmap allocmap;
arraypoolulong allocmapbytes(struct allocmap *tree);
void allocmapdeletepoint(struct allocmap *tree,starreal x,starreal y,starreal z);
proxipoolulong allocmapnewpoint(struct allocmap *tree,starreal x,starreal y,starreal z);
proxipoolulong allocmapindex(struct allocmap *tree,starreal x,starreal y,starreal z);
typedef struct allocmapnode allocmapnode;
void allocmapremoveroot(struct allocmapnode **treeroot);
void allocmapinsertroot(struct allocmapnode **treeroot,struct allocmapnode *insertnode,int splayside);
void allocmapmax(struct allocmapnode **treeroot);
int allocmapsplay(struct allocmapnode **treeroot,starreal x,starreal y,starreal z,struct allocmapnode **nearnode);
struct allocmapnode *allocmapnewnode(struct allocmap *tree);
void allocmapdeinit(struct allocmap *tree);
void allocmapinit(struct allocmap *tree,int verbose);
void allocmaprestart(struct allocmap *tree);
struct allocmap {
  struct arraypool nodearray;      /* Tiered array of allocation tree nodes. */
  struct allocmapnode *allocroot;                /* Root of allocation tree. */
  struct allocmapnode *spareroot;                /* Root of spare node tree. */
  int verbosity;                /* Amount of debugging information to print. */
};
struct allocmapnode {
  struct allocmapnode *left, *right;          /* My left and right children. */
  starreal xsam, ysam, zsam;     /* Coordinates of this node's sample point. */
  proxipoolulong index;                      /* My index (in the arraypool). */
};
#define LOG2OCTREENODESPERBLOCK 8
int zorderbefore(starreal x1,starreal y1,starreal z1,starreal x2,starreal y2,starreal z2);
arraypoolulong proxipoolbytes(struct proxipool *pool);
arraypoolulong proxipoolobjects(struct proxipool *pool);
void proxipoolfree(struct proxipool *pool,tag killtag);
tag proxipoolnew(struct proxipool *pool,proxipoolulong allocindex,void **outobject);
void proxipoolinitpoolpools(struct proxipool *pool,proxipoolulong endindex);
tag proxipooliterate(struct proxipool *pool,tag thistag);
#define proxipooltag2allocindex(pool, searchtag)  \
  (proxipooltag2mini(pool, searchtag)->allocindex)
void proxipooldeinit(struct proxipool *pool);
void proxipoolinit(struct proxipool *pool,size_t objectbytes1,size_t objectbytes2,int verbose);
void proxipoolrestart(struct proxipool *pool);
void proxipoolrestartmini(struct proxipool *pool,struct minipoolheader *mini);
typedef struct poolpool poolpool;
struct poolpool {
  tag freelisthead;            /* Head of list of minipools with free space. */
  tag freelisttail;            /* Tail of list of minipools with free space. */
  tag mygroup;                 /* Next minipool to be allocated in my group. */
};
typedef unsigned short miniindex;
struct minipoolheader {
  char *object1block;    /* Pointer to the block of objects in the minipool. */
  char *object2block;          /* Optional pointer to supplementary objects. */
  proxipoolulong allocindex;                       /* Index of the poolpool. */
  tag nextminifree;     /* Next in linked list of minipools with free space. */
  miniindex firstvirgin;        /* First never-allocated object in minipool. */
  miniindex freestack; /* Head of linked stack of freed objects in minipool. */
};
#define LOG2POOLPOOLSPERBLOCK 8
#define MINISPERGROUP 8
#define NOTAMINIINDEX ((miniindex) ~0)
#define NOTATAG ((tag) ~0)
arraypoolulong arraypoolbytes(struct arraypool *pool);
arraypoolulong arraypoolallocated(struct arraypool *pool);
void arraypoolfreeindex(struct arraypool *pool,arraypoolulong dyingindex);
arraypoolulong arraypoolnewindex(struct arraypool *pool,void **newptr);
void arraypoolfreeptr(struct arraypool *pool,void *dyingobject);
void *arraypoolnewptr(struct arraypool *pool);
void *arraypoollookup(struct arraypool *pool,arraypoolulong index);
void *arraypoolforcelookup(struct arraypool *pool,arraypoolulong index);
char *arraypoolsecondtier(struct arraypool *pool,arraypoolulong index);
void arraypooldeinit(struct arraypool *pool);
void arraypoolinit(struct arraypool *pool,arraypoolulong objectbytes,arraypoolulong log2objectsperblock,int alloctype);
void arraypoolrestart(struct arraypool *pool);
#define NOTAPOOLINDEX ((arraypoolulong) ~0)
#define TOPRESIZEFACTOR 3
#define TOPARRAYSTARTSIZE 128
unsigned long randomnation(unsigned long choices);
extern unsigned long randomseed;
void parsecommandline(int argc,char **argv,struct behavior *b);
#if !defined(STARLIBRARY)
void info(void);
void syntax(void);
#endif
void starfree(void *memptr);
void *starmalloc(size_t size);
void starexit(int status);
extern starreal isperrboundA,isperrboundB,isperrboundC;
extern starreal o3derrboundA,o3derrboundB,o3derrboundC;
extern starreal o2derrboundA,o2derrboundB,o2derrboundC;
extern starreal resulterrbound;
extern starreal epsilon;
extern starreal splitter;
typedef ptrdiff_t starlong;
#define FILENAMESIZE 2048
struct behavior {

/*  Switches for the tetrahedralizer.                                        */
/*  Read the instructions to find out the meaning of these switches.         */

  int poly;                                                    /* -p switch. */
  int refine;                                                  /* -r switch. */
  int quality;                                                 /* -q switch. */
  /* Maximum acceptable tetrahedron circumradius-to-shortest edge ratio:     */
  starreal qmeasure;                           /* Specified after -q switch. */
  starreal minangle;          /* Min dehedral angle bound, after -q/ switch. */
  starreal goodangle;                         /* Cosine squared of minangle. */
  int varvolume;                      /* -a switch without number following. */
  int fixedvolume;                       /* -a switch with number following. */
  starreal maxvolume;    /* Maximum volume bound, specified after -a switch. */
  int usertest;                                                /* -u switch. */
  int regionattrib;                                            /* -A switch. */
  int convex;                                                  /* -c switch. */
  int weighted;                         /* 1 for -w switch, 2 for -W switch. */
  int conformdel;                                              /* -D switch. */
  int jettison;                                                /* -j switch. */
  int edgesout;                                                /* -e switch. */
  int facesout;                                                /* -f switch. */
  int voronoi;                                                 /* -v switch. */
  int neighbors;                                               /* -n switch. */
  int geomview;                                                /* -g switch. */
  int nobound;                                                 /* -B switch. */
  int nopolywritten;                                           /* -P switch. */
  int nonodewritten;                                           /* -N switch. */
  int noelewritten;                                            /* -E switch. */
  int noiterationnum;                                          /* -I switch. */
  int noholes;                                                 /* -O switch. */
  int noexact;                                                 /* -X switch. */
  /* All items are numbered starting from `firstnumber':                     */
  starulong firstnumber;                            /* Inverse of -z switch. */
  int order;                    /* Element order, specified after -o switch. */
  int nobisect;                 /* Count of how often -Y switch is selected. */
  starlong steiner;   /* Max # of Steiner points, specified after -S switch. */
  int jumpwalk;                                                /* -J switch. */
  int norandom;                                                /* -k switch. */
  int fullrandom;                                              /* -K switch. */
  int docheck;                                                 /* -C switch. */
  int quiet;                                                   /* -Q switch. */
  int verbose;                  /* Count of how often -V switch is selected. */
  /* Determines whether new vertices will be added, other than the input:    */
  int addvertices;                              /* -p, -q, -a, or -u switch. */
  /* Determines whether segments and facets are used at all:                 */
  int usefacets;                        /* -p, -r, -q, -a, -u, or -c switch. */

  int readnodefileflag;                       /* Has a .node file been read? */

/*  Variables for file names.                                                */

#ifndef STARLIBRARY
  char innodefilename[FILENAMESIZE];                    /* Input .node file. */
  char inelefilename[FILENAMESIZE];                      /* Input .ele file. */
  char inpolyfilename[FILENAMESIZE];                    /* Input .poly file. */
  char areafilename[FILENAMESIZE];                      /* Input .area file. */
  char outnodefilename[FILENAMESIZE];                  /* Output .node file. */
  char outelefilename[FILENAMESIZE];                    /* Output .ele file. */
  char outpolyfilename[FILENAMESIZE];                  /* Output .poly file. */
  char edgefilename[FILENAMESIZE];                     /* Output .edge file. */
  char facefilename[FILENAMESIZE];                     /* Output .face file. */
  char vnodefilename[FILENAMESIZE];                  /* Output .v.node file. */
  char vpolyfilename[FILENAMESIZE];                  /* Output .v.poly file. */
  char neighborfilename[FILENAMESIZE];                /* Output .neigh file. */
  char offfilename[FILENAMESIZE];                       /* Output .off file. */
#endif /* not STARLIBRARY */

/*  Counts of operations performed.                                          */

  starulong inspherecount;            /* Number of insphere tests performed. */
  starulong orientcount;        /* Number of 3D orientation tests performed. */
  starulong orient4dcount;      /* Number of 4D orientation tests performed. */
  starulong tetcircumcentercount;/* Number of tet circumcenter calculations. */
  starulong tricircumcentercount;    /* Triangular face circumcenter calc's. */

};
#define PI 3.141592653589793238462643383279502884197169399375105820974944592308
#define INPUTLINESIZE 1024
#define INEXACT /* Nothing */
#define INTERFACE 0


<|start_filename|>vtkVmtk/Contrib/vtkvmtkBoundaryLayerGenerator2.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkBoundaryLayerGenerator2.h,v $
  Language:  C++
  Date:      $$
  Version:   $$

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

  Note: this class was contributed by 
	<NAME>
	Kalkulo AS
	Simula Research Laboratory
=========================================================================*/
// .NAME vtkvmtkBoundaryLayerGenerator2 - Extended version of vtkvmtkBoundaryLayerGenerator 
// .SECTION Description
// This version allows finer control on the surfaces to be included. If the original surface has open profiles, a surface can be extracted from them as well. The points on the open profiles may be specified with an array (OpenProfilesIdsArrayName). A value of -1 in this array specifies a point on the interior of the surface. Cell entity ids can also be output for the volume and surface elements. Surface elements are numbered in increasing numbers, using the openProfilesIds if specified.

#ifndef __vtkvmtkBoundaryLayerGenerator2_h
#define __vtkvmtkBoundaryLayerGenerator2_h

#include "vtkvmtkBoundaryLayerGenerator.h"
#include "vtkvmtkWin32Header.h"

class vtkPoints;
class vtkDataArray;
class vtkOrderedTriangulator;

class VTK_VMTK_CONTRIB_EXPORT vtkvmtkBoundaryLayerGenerator2 : public vtkvmtkBoundaryLayerGenerator
{
  public: 
  vtkTypeMacro(vtkvmtkBoundaryLayerGenerator2,vtkvmtkBoundaryLayerGenerator);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkBoundaryLayerGenerator2 *New();

  // vtkGetStringMacro(CellEntityIdsArrayName);
  // vtkSetStringMacro(CellEntityIdsArrayName);
  
  vtkGetStringMacro(OpenProfilesIdsArrayName);
  vtkSetStringMacro(OpenProfilesIdsArrayName);

  //Description:
  //Include/Exclude the different surfaces into the resulting unstructures grud
  //If IncludeSurfaceCells is set to 1 all of the surfaces are included
  vtkGetMacro(IncludeExtrudedOpenProfilesCells,int);
  vtkSetMacro(IncludeExtrudedOpenProfilesCells,int);
  vtkBooleanMacro(IncludeExtrudedOpenProfilesCells,int);
  
  vtkGetMacro(IncludeExtrudedSurfaceCells,int);
  vtkSetMacro(IncludeExtrudedSurfaceCells,int);
  vtkBooleanMacro(IncludeExtrudedSurfaceCells,int);
  
  vtkGetMacro(IncludeOriginalSurfaceCells,int);
  vtkSetMacro(IncludeOriginalSurfaceCells,int);
  vtkBooleanMacro(IncludeOriginalSurfaceCells,int);

  //Description:
  //Id assigned to the volumetric layer in the CellEntityIds array
  vtkGetMacro(LayerEntityId,int);
  vtkSetMacro(LayerEntityId,int);

  //Description:
  //Entity Id of the first surface element of the layer.
  vtkGetMacro(SurfaceEntityId,int);
  vtkSetMacro(SurfaceEntityId,int);
  
  //Description
  //Entity Id of the first open profile of the layer
  vtkGetMacro(OpenProfilesEntityId,int);
  vtkSetMacro(OpenProfilesEntityId,int);

  protected:
  vtkvmtkBoundaryLayerGenerator2();
  ~vtkvmtkBoundaryLayerGenerator2();

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  // char *CellEntityIdsArrayName;
 
 //A per-vertex array indicating which vertices are situated on the open profiles of the surface.
 //Elements with value -1 are assumed to be on the inner surface
  char *OpenProfilesIdsArrayName;
  
  int IncludeExtrudedOpenProfilesCells;
  int IncludeExtrudedSurfaceCells;
  int IncludeOriginalSurfaceCells;

  int LayerEntityId;
  int SurfaceEntityId;
  int OpenProfilesEntityId;

  // Used to triangulate 3D cells
  vtkOrderedTriangulator *Triangulator;

  private:
  vtkvmtkBoundaryLayerGenerator2(const vtkvmtkBoundaryLayerGenerator2&);  // Not implemented.
  void operator=(const vtkvmtkBoundaryLayerGenerator2&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Contrib/vtkvmtkPolyDataGeodesicRBFInterpolation.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkPolyDataGeodesicRBFInterpolation.cxx,v $
  Language:  C++
  Date:      $$
  Version:   $$

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

  Note: this class was contributed by 
	<NAME>
	Kalkulo AS
	Simula Research Laboratory
=========================================================================*/

#include "vtkvmtkPolyDataGeodesicRBFInterpolation.h"

#include "vtkVersion.h"
#include "vtkPointData.h"
#include "vtkMath.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkIOStream.h"
#include "vtkFloatArray.h"
#include "vtkDoubleArray.h"

#include <vector>

#include "vtkvmtkConstants.h"

#if (VTK_MAJOR_VERSION > 5)
#include "vtkDijkstraGraphGeodesicPath.h"
#else
#if (VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION >= 2)
#include "vtkDijkstraGraphGeodesicPath.h"
#endif
#endif


vtkStandardNewMacro(vtkvmtkPolyDataGeodesicRBFInterpolation);

vtkvmtkPolyDataGeodesicRBFInterpolation::vtkvmtkPolyDataGeodesicRBFInterpolation() 
{
  this->InterpolatedArrayName = NULL;

  this->SeedIds = NULL;
  this->SeedValues = NULL;
  
  this->RBFType = THIN_PLATE_SPLINE;
}

vtkvmtkPolyDataGeodesicRBFInterpolation::~vtkvmtkPolyDataGeodesicRBFInterpolation()
{
  if (this->InterpolatedArrayName)
    {
    delete[] this->InterpolatedArrayName;
    this->InterpolatedArrayName = NULL;
    }

  if (this->SeedIds)
    {
    this->SeedIds->Delete();
    this->SeedIds = NULL;
    }
    
  if (this->SeedValues)
    {
    this->SeedValues->Delete();
    this->SeedValues = NULL;
    }
}

double vtkvmtkPolyDataGeodesicRBFInterpolation::EvaluateRBF(double r)
{
  if (this->RBFType == THIN_PLATE_SPLINE)
    {
    double r2 = r*r;
    if (!r2)
      {
      return 0.0;
      }
    return r2 * log(sqrt(r2));
    }
  else if (this->RBFType == BIHARMONIC)
    {
    return r;
    }
  else if (this->RBFType == TRIHARMONIC)
    {
    return r*r*r;
    }
  else
    {
    vtkErrorMacro(<<"Error: Unsupported RBFType!");
    return 0.0;
    }
}


int vtkvmtkPolyDataGeodesicRBFInterpolation::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
#if (VTK_MAJOR_VERSION<5) || ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION != 2) && (VTK_MINOR_VERSION<5))
  vtkErrorMacro(<<"You must have vtk == 5.2 or vtk >= 5.5 to use this feature");
    return 1;
#else

  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (!this->InterpolatedArrayName)
    {
    vtkErrorMacro(<<"InterpolatedArrayName not set.");
    return 1;
    }

  if (!this->SeedIds)
    {
    vtkErrorMacro(<<"SeedIds not set");
    return 1;
    }
    
  if (!this->SeedValues)
    {
    vtkErrorMacro(<<"SeedValues not set");
    return 1;
    }


  int numberOfSeeds = this->SeedIds->GetNumberOfIds();

  int numberOfInputPoints = input->GetNumberOfPoints();

  if ((numberOfSeeds != this->SeedValues->GetNumberOfTuples()) || (numberOfSeeds>numberOfInputPoints) || (numberOfSeeds<2))
    {
    vtkErrorMacro(<<"Incorrect number of seed values");
    return 1;
    }
  
  output->DeepCopy(input);

  
  vtkDataArray* interpolatedArray =  output->GetPointData()->GetArray(this->InterpolatedArrayName);
  
  bool createArray = !interpolatedArray;
  
  if (createArray) 
    {
    interpolatedArray = vtkDoubleArray::New();
    interpolatedArray->SetName(this->InterpolatedArrayName);
    interpolatedArray->SetNumberOfComponents(1);
    interpolatedArray->SetNumberOfTuples(numberOfInputPoints);
  
    output->GetPointData()->AddArray(interpolatedArray);
    }

  
  
  vtkDijkstraGraphGeodesicPath *dijkstraAlgo = vtkDijkstraGraphGeodesicPath::New();
#if (VTK_MAJOR_VERSION <= 5)
  dijkstraAlgo->SetInput(input);
#else
  dijkstraAlgo->SetInputData(input);
#endif
  dijkstraAlgo->StopWhenEndReachedOff();
  dijkstraAlgo->UseScalarWeightsOff();
  
  std::vector<vtkDoubleArray *> geodesicDistances;
  
  
  //Compute the geodesic distances
  for (int i=0; i<numberOfSeeds; i++)
    {
    dijkstraAlgo->SetStartVertex(SeedIds->GetId(i));
    dijkstraAlgo->Update();
    vtkDoubleArray *seedDistances = vtkDoubleArray::New();
    dijkstraAlgo->GetCumulativeWeights(seedDistances);
    geodesicDistances.push_back(seedDistances);
    }
    
  //Compute the coefficients  
  double **A, *x;
  x = new double[numberOfSeeds];
  A = new double* [numberOfSeeds];

  int i;
  for (i=0; i<numberOfSeeds; i++)
    {
    A[i] = new double[numberOfSeeds];
    x[i] = this->SeedValues->GetComponent(i,0);
    }

  int j;
  for (i=0; i<numberOfSeeds; i++)
    {
    for (j=0; j<numberOfSeeds; j++)
      {
      double dist = geodesicDistances[i]->GetValue(this->SeedIds->GetId(j));
      A[i][j] = this->EvaluateRBF(dist);
      }
    } 

  cout << "A " << endl;
  for (int i=0;i<numberOfSeeds;i++) {
    for (int j=0;j<numberOfSeeds;j++) {
      cout << A[i][j] << " ";
    }
    cout << endl;
  }
  
  cout << "b " << endl;
  for (int i=0;i<numberOfSeeds;i++) {
    cout << x[i] << endl;
  }

  int ret = vtkMath::SolveLinearSystem(A,x,numberOfSeeds);
  
  cout << "x " << endl;
  for (int i=0;i<numberOfSeeds;i++) {
    cout << x[i] << endl;
  }
  
  if (!ret)
    {
    vtkErrorMacro(<<"Cannot compute coefficients: error during linear system solve");
    }

  
  for (i=0; i<numberOfSeeds; i++)
    {
    delete[] A[i];
    }
  delete[] A;
  
  
  //Interpolate the values at all points using the coefficients
  for (int i=0;i<numberOfInputPoints;i++) 
    {
    double rbfValue = 0.;
    for (int j=0;j<numberOfSeeds;j++) {
      double dist = geodesicDistances[j]->GetValue(i);
      rbfValue += x[j]*this->EvaluateRBF(dist);
    }
    interpolatedArray->SetComponent(i,0,rbfValue);
    }
  
  delete[] x;
  for (int i=0;i<numberOfSeeds;i++)
    {
    geodesicDistances[i]->Delete();
    }
  
  geodesicDistances.clear();


  if (createArray) interpolatedArray->Delete();

  return 1;
#endif
}


<|start_filename|>vtkVmtk/IO/vtkvmtkXdaWriter.h<|end_filename|>
/*=========================================================================
                                                                                                                                    
Program:   VMTK
Module:    $RCSfile: vtkvmtkXdaWriter.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:47:47 $
Version:   $Revision: 1.2 $
                                                                                                                                    
  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.
                                                                                                                                    
=========================================================================*/
// .NAME vtkvmtkXdaWriter - writes libmesh Xda files
// .SECTION Description
// vtkvmtkXdaWriter writes libmesh Xda files
//
// .SECTION See Also

#ifndef __vtkvmtkXdaWriter_h
#define __vtkvmtkXdaWriter_h

#include "vtkvmtkWin32Header.h"
#include "vtkUnstructuredGridWriter.h"

class vtkCell;
class vtkIdList;

class VTK_VMTK_IO_EXPORT vtkvmtkXdaWriter : public vtkUnstructuredGridWriter
{
public:
  static vtkvmtkXdaWriter *New();
  vtkTypeMacro(vtkvmtkXdaWriter,vtkUnstructuredGridWriter);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE;

  vtkSetStringMacro(BoundaryDataArrayName);
  vtkGetStringMacro(BoundaryDataArrayName);

protected:
  vtkvmtkXdaWriter();
  ~vtkvmtkXdaWriter();

  void WriteData() VTK_OVERRIDE;

  static void GetLibmeshConnectivity(int cellType, vtkIdList* libmeshConnectivity);
  static void GetLibmeshFaceOrder(int cellType, vtkIdList* libmeshFaceOrder);

  char* BoundaryDataArrayName;

private:
  vtkvmtkXdaWriter(const vtkvmtkXdaWriter&);  // Not implemented.
  void operator=(const vtkvmtkXdaWriter&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBifurcationSections.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkPolyDataBifurcationSections.cxx,v $
Language:  C++
Date:      $Date: 2006/10/17 15:16:16 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataBifurcationSections.h"
#include "vtkPolyData.h"
#include "vtkPointData.h"
#include "vtkCellData.h"
#include "vtkCellArray.h"
#include "vtkDoubleArray.h"
#include "vtkIntArray.h"
#include "vtkMath.h"
#include "vtkvmtkCenterlineSphereDistance.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkCenterlineUtilities.h"
#include "vtkvmtkCenterlineBifurcationVectors.h"
#include "vtkvmtkPolyDataBranchUtilities.h"
#include "vtkvmtkPolyDataBranchSections.h"


vtkStandardNewMacro(vtkvmtkPolyDataBifurcationSections);

vtkvmtkPolyDataBifurcationSections::vtkvmtkPolyDataBifurcationSections()
{
  this->GroupIdsArrayName = NULL;

  this->Centerlines = NULL;

  this->CenterlineRadiusArrayName = NULL;
  this->CenterlineGroupIdsArrayName = NULL;
  this->CenterlineIdsArrayName = NULL;
  this->CenterlineTractIdsArrayName = NULL;
  this->BlankingArrayName = NULL;

  this->BifurcationSectionGroupIdsArrayName = NULL;
  this->BifurcationSectionBifurcationGroupIdsArrayName = NULL;
  this->BifurcationSectionPointArrayName = NULL;
  this->BifurcationSectionNormalArrayName = NULL;
  this->BifurcationSectionAreaArrayName = NULL;
  this->BifurcationSectionMinSizeArrayName = NULL;
  this->BifurcationSectionMaxSizeArrayName = NULL;
  this->BifurcationSectionShapeArrayName = NULL;
  this->BifurcationSectionClosedArrayName = NULL;
  this->BifurcationSectionOrientationArrayName = NULL;
  this->BifurcationSectionDistanceSpheresArrayName = NULL;

  this->NumberOfDistanceSpheres = 1;
}

vtkvmtkPolyDataBifurcationSections::~vtkvmtkPolyDataBifurcationSections()
{
  if (this->GroupIdsArrayName)
    {
    delete[] this->GroupIdsArrayName;
    this->GroupIdsArrayName = NULL;
    }

  if (this->Centerlines)
    {
    this->Centerlines->Delete();
    this->Centerlines = NULL;
    }

  if (this->CenterlineRadiusArrayName)
    {
    delete[] this->CenterlineRadiusArrayName;
    this->CenterlineRadiusArrayName = NULL;
    }

  if (this->CenterlineGroupIdsArrayName)
    {
    delete[] this->CenterlineGroupIdsArrayName;
    this->CenterlineGroupIdsArrayName = NULL;
    }

  if (this->CenterlineIdsArrayName)
    {
    delete[] this->CenterlineIdsArrayName;
    this->CenterlineIdsArrayName = NULL;
    }

  if (this->CenterlineTractIdsArrayName)
    {
    delete[] this->CenterlineTractIdsArrayName;
    this->CenterlineTractIdsArrayName = NULL;
    }

  if (this->BlankingArrayName)
    {
    delete[] this->BlankingArrayName;
    this->BlankingArrayName = NULL;
    }

  if (this->BifurcationSectionGroupIdsArrayName)
    {
    delete[] this->BifurcationSectionGroupIdsArrayName;
    this->BifurcationSectionGroupIdsArrayName = NULL;
    }

  if (this->BifurcationSectionBifurcationGroupIdsArrayName)
    {
    delete[] this->BifurcationSectionBifurcationGroupIdsArrayName;
    this->BifurcationSectionBifurcationGroupIdsArrayName = NULL;
    }

  if (this->BifurcationSectionPointArrayName)
    {
    delete[] this->BifurcationSectionPointArrayName;
    this->BifurcationSectionPointArrayName = NULL;
    }

  if (this->BifurcationSectionNormalArrayName)
    {
    delete[] this->BifurcationSectionNormalArrayName;
    this->BifurcationSectionNormalArrayName = NULL;
    }

  if (this->BifurcationSectionAreaArrayName)
    {
    delete[] this->BifurcationSectionAreaArrayName;
    this->BifurcationSectionAreaArrayName = NULL;
    }

  if (this->BifurcationSectionMinSizeArrayName)
    {
    delete[] this->BifurcationSectionMinSizeArrayName;
    this->BifurcationSectionMinSizeArrayName = NULL;
    }

  if (this->BifurcationSectionMaxSizeArrayName)
    {
    delete[] this->BifurcationSectionMaxSizeArrayName;
    this->BifurcationSectionMaxSizeArrayName = NULL;
    }

  if (this->BifurcationSectionShapeArrayName)
    {
    delete[] this->BifurcationSectionShapeArrayName;
    this->BifurcationSectionShapeArrayName = NULL;
    }

  if (this->BifurcationSectionClosedArrayName)
    {
    delete[] this->BifurcationSectionClosedArrayName;
    this->BifurcationSectionClosedArrayName = NULL;
    }

  if (this->BifurcationSectionOrientationArrayName)
    {
    delete[] this->BifurcationSectionOrientationArrayName;
    this->BifurcationSectionOrientationArrayName = NULL;
    }

  if (this->BifurcationSectionDistanceSpheresArrayName)
    {
    delete[] this->BifurcationSectionDistanceSpheresArrayName;
    this->BifurcationSectionDistanceSpheresArrayName = NULL;
    }
}

int vtkvmtkPolyDataBifurcationSections::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (!this->GroupIdsArrayName)
    {
    vtkErrorMacro(<<"GroupIdsArrayName not specified");
    return 1;
    }

  vtkDataArray* groupIdsArray = input->GetPointData()->GetArray(this->GroupIdsArrayName);

  if (!groupIdsArray)
    {
    vtkErrorMacro(<<"GroupIdsArray with name specified does not exist");
    return 1;
    }

  if (!this->Centerlines)
    {
    vtkErrorMacro(<<"Centerlines not set");
    return 1;
    }

  if (!this->CenterlineRadiusArrayName)
    {
    vtkErrorMacro(<<"CenterlineRadiusArrayName not specified");
    return 1;
    }

  vtkDataArray* centerlineRadiusArray = this->Centerlines->GetPointData()->GetArray(this->CenterlineRadiusArrayName);

  if (!centerlineRadiusArray)
    {
    vtkErrorMacro(<<"CenterlineRadiusArray with name specified does not exist");
    return 1;
    }

  if (!this->CenterlineGroupIdsArrayName)
    {
    vtkErrorMacro(<<"CenterlineGroupIdsArrayName not specified");
    return 1;
    }

  vtkDataArray* centerlineGroupIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineGroupIdsArrayName);

  if (!centerlineGroupIdsArray)
    {
    vtkErrorMacro(<<"CenterlineGroupIdsArray with name specified does not exist");
    return 1;
    }

  if (!this->CenterlineIdsArrayName)
    {
    vtkErrorMacro(<<"CenterlineIdsArrayName not specified");
    return 1;
    }

  vtkDataArray* centerlineIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineIdsArrayName);

  if (!centerlineIdsArray)
    {
    vtkErrorMacro(<<"CenterlineIdsArray with name specified does not exist");
    return 1;
    }

  if (!this->CenterlineTractIdsArrayName)
    {
    vtkErrorMacro(<<"CenterlineTractIdsArrayName not specified");
    return 1;
    }

  vtkDataArray* centerlineTractIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineTractIdsArrayName);

  if (!centerlineTractIdsArray)
    {
    vtkErrorMacro(<<"CenterlineTractIdsArray with name specified does not exist");
    return 1;
    }

  if (!this->BlankingArrayName)
    {
    vtkErrorMacro(<<"BlankingArrayName not specified");
    return 1;
    }

  vtkDataArray* blankingArray = this->Centerlines->GetCellData()->GetArray(this->BlankingArrayName);

  if (!blankingArray)
    {
    vtkErrorMacro(<<"BlankingArray with name specified does not exist");
    return 1;
    }

  if (!this->BifurcationSectionGroupIdsArrayName)
    {
    vtkErrorMacro(<<"BifurcationSectionGroupIdsArrayName not specified");
    return 1;
    }

  if (!this->BifurcationSectionBifurcationGroupIdsArrayName)
    {
    vtkErrorMacro(<<"BifurcationSectionBifurcationGroupIdsArrayName not specified");
    return 1;
    }

  if (!this->BifurcationSectionPointArrayName)
    {
    vtkErrorMacro(<<"BifurcationSectionPointArrayName not specified");
    return 1;
    }

  if (!this->BifurcationSectionNormalArrayName)
    {
    vtkErrorMacro(<<"BifurcationSectionNormalArrayName not specified");
    return 1;
    }

  if (!this->BifurcationSectionAreaArrayName)
    {
    vtkErrorMacro(<<"BifurcationSectionAreaArrayName not specified");
    return 1;
    }

  if (!BifurcationSectionMinSizeArrayName)
    {
    vtkErrorMacro(<<"BifurcationSectionMinSizeArrayName not specified");
    return 1;
    }

  if (!BifurcationSectionMaxSizeArrayName)
    {
    vtkErrorMacro(<<"BifurcationSectionMaxSizeArrayName not specified");
    return 1;
    }

  if (!BifurcationSectionShapeArrayName)
    {
    vtkErrorMacro(<<"BifurcationSectionShapeArrayName not specified");
    return 1;
    }

  if (!BifurcationSectionClosedArrayName)
    {
    vtkErrorMacro(<<"BifurcationSectionClosedArrayName not specified");
    return 1;
    }

  if (!BifurcationSectionOrientationArrayName)
    {
    vtkErrorMacro(<<"BifurcationSectionOrientationArrayName not specified");
    return 1;
    }

  if (!BifurcationSectionDistanceSpheresArrayName)
    {
    vtkErrorMacro(<<"BifurcationSectionDistanceSpheresArrayName not specified");
    return 1;
    }

  vtkIntArray* bifurcationSectionGroupIdsArray = vtkIntArray::New();
  bifurcationSectionGroupIdsArray->SetName(this->BifurcationSectionGroupIdsArrayName);

  vtkIntArray* bifurcationSectionBifurcationGroupIdsArray = vtkIntArray::New();
  bifurcationSectionBifurcationGroupIdsArray->SetName(this->BifurcationSectionBifurcationGroupIdsArrayName);

  vtkDoubleArray* bifurcationSectionPointArray = vtkDoubleArray::New();
  bifurcationSectionPointArray->SetName(this->BifurcationSectionPointArrayName);
  bifurcationSectionPointArray->SetNumberOfComponents(3);

  vtkDoubleArray* bifurcationSectionNormalArray = vtkDoubleArray::New();
  bifurcationSectionNormalArray->SetName(this->BifurcationSectionNormalArrayName);
  bifurcationSectionNormalArray->SetNumberOfComponents(3);

  vtkDoubleArray* bifurcationSectionAreaArray = vtkDoubleArray::New();
  bifurcationSectionAreaArray->SetName(this->BifurcationSectionAreaArrayName);

  vtkDoubleArray* bifurcationSectionShapeArray = vtkDoubleArray::New();
  bifurcationSectionShapeArray->SetName(this->BifurcationSectionShapeArrayName);

  vtkDoubleArray* bifurcationSectionMinSizeArray = vtkDoubleArray::New();
  bifurcationSectionMinSizeArray->SetName(this->BifurcationSectionMinSizeArrayName);

  vtkDoubleArray* bifurcationSectionMaxSizeArray = vtkDoubleArray::New();
  bifurcationSectionMaxSizeArray->SetName(this->BifurcationSectionMaxSizeArrayName);

  vtkIntArray* bifurcationSectionClosedArray = vtkIntArray::New();
  bifurcationSectionClosedArray->SetName(this->BifurcationSectionClosedArrayName);

  vtkIntArray* bifurcationSectionOrientationArray = vtkIntArray::New();
  bifurcationSectionOrientationArray->SetName(this->BifurcationSectionOrientationArrayName);
  
  vtkIntArray* bifurcationSectionDistanceSpheresArray = vtkIntArray::New();
  bifurcationSectionDistanceSpheresArray->SetName(this->BifurcationSectionDistanceSpheresArrayName);

  output->GetCellData()->AddArray(bifurcationSectionGroupIdsArray);
  output->GetCellData()->AddArray(bifurcationSectionBifurcationGroupIdsArray);
  output->GetCellData()->AddArray(bifurcationSectionPointArray);
  output->GetCellData()->AddArray(bifurcationSectionNormalArray);
  output->GetCellData()->AddArray(bifurcationSectionAreaArray);
  output->GetCellData()->AddArray(bifurcationSectionMinSizeArray);
  output->GetCellData()->AddArray(bifurcationSectionMaxSizeArray);
  output->GetCellData()->AddArray(bifurcationSectionShapeArray);
  output->GetCellData()->AddArray(bifurcationSectionClosedArray);
  output->GetCellData()->AddArray(bifurcationSectionOrientationArray);
  output->GetCellData()->AddArray(bifurcationSectionDistanceSpheresArray);

  vtkPoints* outputPoints = vtkPoints::New();
  vtkCellArray* outputPolys = vtkCellArray::New();

  output->SetPoints(outputPoints);
  output->SetPolys(outputPolys);

  vtkIdList* blankedGroupIds = vtkIdList::New();
  vtkvmtkCenterlineUtilities::GetBlankedGroupsIdList(this->Centerlines,this->CenterlineGroupIdsArrayName,this->BlankingArrayName,blankedGroupIds);
  int i;
  for (i=0; i<blankedGroupIds->GetNumberOfIds(); i++)
  {
    vtkIdType bifurcationGroupId = blankedGroupIds->GetId(i);

    //compute quantities and insert proper values in arrays
    vtkIdList* upStreamGroupIds = vtkIdList::New();
    vtkIdList* downStreamGroupIds = vtkIdList::New();
    
    vtkvmtkCenterlineUtilities::FindAdjacentCenterlineGroupIds(this->Centerlines,this->CenterlineGroupIdsArrayName,this->CenterlineIdsArrayName,this->CenterlineTractIdsArrayName,bifurcationGroupId,upStreamGroupIds,downStreamGroupIds);
    
    this->ComputeBifurcationSections(input,bifurcationGroupId,upStreamGroupIds,downStreamGroupIds,output);
    
    upStreamGroupIds->Delete();
    downStreamGroupIds->Delete();
    }

  blankedGroupIds->Delete();

  outputPoints->Delete();
  outputPolys->Delete();
  
  bifurcationSectionGroupIdsArray->Delete();
  bifurcationSectionBifurcationGroupIdsArray->Delete();
  bifurcationSectionPointArray->Delete();
  bifurcationSectionNormalArray->Delete();
  bifurcationSectionAreaArray->Delete();
  bifurcationSectionShapeArray->Delete();
  bifurcationSectionMinSizeArray->Delete();
  bifurcationSectionMaxSizeArray->Delete();
  bifurcationSectionClosedArray->Delete();
  bifurcationSectionOrientationArray->Delete();
  bifurcationSectionDistanceSpheresArray->Delete();

  return 1;
}

void vtkvmtkPolyDataBifurcationSections::ComputeBifurcationSections(vtkPolyData* input, int bifurcationGroupId, vtkIdList* upStreamGroupIds, vtkIdList* downStreamGroupIds, vtkPolyData* output)
{
  vtkDataArray* radiusArray = this->Centerlines->GetPointData()->GetArray(this->CenterlineRadiusArrayName);
  vtkPoints* outputPoints = output->GetPoints();
  vtkCellArray* outputPolys = output->GetPolys();
  vtkDoubleArray* bifurcationSectionPointArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationSectionPointArrayName));
  vtkDoubleArray* bifurcationSectionNormalArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationSectionNormalArrayName));
  vtkDoubleArray* bifurcationSectionAreaArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationSectionAreaArrayName));
  vtkDoubleArray* bifurcationSectionMinSizeArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationSectionMinSizeArrayName));
  vtkDoubleArray* bifurcationSectionMaxSizeArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationSectionMaxSizeArrayName));
  vtkDoubleArray* bifurcationSectionShapeArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationSectionShapeArrayName));
  vtkIntArray* bifurcationSectionClosedArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationSectionClosedArrayName));
  vtkIntArray* bifurcationSectionOrientationArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationSectionOrientationArrayName));
  vtkIntArray* bifurcationSectionDistanceSpheresArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationSectionDistanceSpheresArrayName));
  vtkIntArray* bifurcationSectionGroupIdsArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationSectionGroupIdsArrayName));
  vtkIntArray* bifurcationSectionBifurcationGroupIdsArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationSectionBifurcationGroupIdsArrayName));
  
  vtkIdList* bifurcationSectionGroupIds = vtkIdList::New();
  vtkIntArray* bifurcationSectionOrientations = vtkIntArray::New();
  
  int numberOfUpStreamGroupIds = upStreamGroupIds->GetNumberOfIds();
  int numberOfDownStreamGroupIds = downStreamGroupIds->GetNumberOfIds();
  int i;
  for (i=0; i<numberOfUpStreamGroupIds; i++)
  {
    bifurcationSectionGroupIds->InsertNextId(upStreamGroupIds->GetId(i));
    bifurcationSectionOrientations->InsertNextValue(vtkvmtkCenterlineBifurcationVectors::VTK_VMTK_UPSTREAM_ORIENTATION);
  }
  for (i=0; i<numberOfDownStreamGroupIds; i++)
  {
    bifurcationSectionGroupIds->InsertNextId(downStreamGroupIds->GetId(i));
    bifurcationSectionOrientations->InsertNextValue(vtkvmtkCenterlineBifurcationVectors::VTK_VMTK_DOWNSTREAM_ORIENTATION);
  }

  int numberOfBifurcationSections = bifurcationSectionGroupIds->GetNumberOfIds();
  
  for (i=0; i<numberOfBifurcationSections; i++)
    {
    int bifurcationSectionGroupId = bifurcationSectionGroupIds->GetId(i);
    int bifurcationSectionOrientation = bifurcationSectionOrientations->GetValue(i);

    double averagePoint[3];
    averagePoint[0] = averagePoint[1] = averagePoint[2] = 0.0;

    double averageTangent[3];
    averageTangent[0] = averageTangent[1] = averageTangent[2] = 0.0;

    double weightSum = 0.0;

    int j;
    bool anyPoint = false;
    vtkIdList* groupCellIds = vtkIdList::New();
    vtkvmtkCenterlineUtilities::GetGroupUniqueCellIds(this->Centerlines,this->CenterlineGroupIdsArrayName,bifurcationSectionGroupId,groupCellIds);
    for (j=0; j<groupCellIds->GetNumberOfIds(); j++)
      {
      vtkIdType cellId = groupCellIds->GetId(j);
      vtkCell* cell = this->Centerlines->GetCell(cellId);
      int numberOfCellPoints = cell->GetNumberOfPoints();
      
      vtkIdType touchingSubId = -1;
      double touchingPCoord = 0.0;
   
      vtkIdType pointSubId = -1;
      double pointPCoord = 0.0;
      bool forward = true;
 
      double lastPoint[3];
      double lastPointRadius = 0.0; 

      if (bifurcationSectionOrientation == vtkvmtkCenterlineBifurcationVectors::VTK_VMTK_UPSTREAM_ORIENTATION)
      {
        pointSubId = numberOfCellPoints-2;
        pointPCoord = 1.0;
        forward = true;
        cell->GetPoints()->GetPoint(numberOfCellPoints-1,lastPoint);
        lastPointRadius = radiusArray->GetComponent(cell->GetPointId(numberOfCellPoints-1),0);
      }
      else if (bifurcationSectionOrientation == vtkvmtkCenterlineBifurcationVectors::VTK_VMTK_DOWNSTREAM_ORIENTATION)
      {
        pointSubId = 0;
        pointPCoord = 0.0;
        forward = false;
        cell->GetPoints()->GetPoint(0,lastPoint);
        lastPointRadius = radiusArray->GetComponent(cell->GetPointId(0),0);
      }
      else
      {
        vtkErrorMacro("Error: invalid BifurcationVectorOrientation");
        return;
      }
    
      vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(this->Centerlines,this->CenterlineRadiusArrayName,cellId,pointSubId,pointPCoord,this->NumberOfDistanceSpheres,touchingSubId,touchingPCoord,forward);
      
      if (touchingSubId == -1)
        {
      	continue;
        }

      anyPoint = true;
      double touchingPoint[3];
      vtkvmtkCenterlineUtilities::InterpolatePoint(this->Centerlines,cellId,touchingSubId,touchingPCoord,touchingPoint);
      
      double touchingPoint0[3], touchingPoint1[3];
      this->Centerlines->GetCell(cellId)->GetPoints()->GetPoint(touchingSubId,touchingPoint0);
      this->Centerlines->GetCell(cellId)->GetPoints()->GetPoint(touchingSubId+1,touchingPoint1);

      double touchingPointTangent[3];
      touchingPointTangent[0] = touchingPoint1[0] - touchingPoint0[0];
      touchingPointTangent[1] = touchingPoint1[1] - touchingPoint0[1];
      touchingPointTangent[2] = touchingPoint1[2] - touchingPoint0[2];

      vtkMath::Normalize(touchingPointTangent);
      double touchingPointRadius = 0.0;
      vtkvmtkCenterlineUtilities::InterpolateTuple1(this->Centerlines,this->CenterlineRadiusArrayName,cellId,touchingSubId,touchingPCoord,touchingPointRadius);

      averagePoint[0] += touchingPointRadius * touchingPointRadius * touchingPoint[0];
      averagePoint[1] += touchingPointRadius * touchingPointRadius * touchingPoint[1];
      averagePoint[2] += touchingPointRadius * touchingPointRadius * touchingPoint[2];

      averageTangent[0] += touchingPointRadius * touchingPointRadius * touchingPointTangent[0];
      averageTangent[1] += touchingPointRadius * touchingPointRadius * touchingPointTangent[1];
      averageTangent[2] += touchingPointRadius * touchingPointRadius * touchingPointTangent[2];

      weightSum += touchingPointRadius * touchingPointRadius;
      }

    if (!anyPoint)
      {
      continue;
      }
      
    averagePoint[0] /= weightSum;
    averagePoint[1] /= weightSum;
    averagePoint[2] /= weightSum;

    averageTangent[0] /= weightSum;
    averageTangent[1] /= weightSum;
    averageTangent[2] /= weightSum;

    vtkMath::Normalize(averageTangent);

    //now cut branch with plane and get section. Compute section properties and store them.
    
    vtkPolyData* cylinder = vtkPolyData::New();
    vtkvmtkPolyDataBranchUtilities::ExtractGroup(input,this->GroupIdsArrayName,bifurcationSectionGroupId,false,cylinder);

    vtkPolyData* section = vtkPolyData::New();
    bool closed = false;
    vtkvmtkPolyDataBranchSections::ExtractCylinderSection(cylinder,averagePoint,averageTangent,section,closed);

    section->BuildCells();
    vtkPoints* sectionCellPoints = section->GetCell(0)->GetPoints();
    int numberOfSectionCellPoints = sectionCellPoints->GetNumberOfPoints();
    outputPolys->InsertNextCell(numberOfSectionCellPoints);
    for (j=0; j<numberOfSectionCellPoints; j++)
    {
      vtkIdType pointId = outputPoints->InsertNextPoint(sectionCellPoints->GetPoint(j));
      outputPolys->InsertCellPoint(pointId);
    }
    
    double area = vtkvmtkPolyDataBranchSections::ComputeBranchSectionArea(section);
    double sizeRange[2];
    double shape = vtkvmtkPolyDataBranchSections::ComputeBranchSectionShape(section,averagePoint,sizeRange);
    int closedValue = closed ? 1 : 0;

    bifurcationSectionGroupIdsArray->InsertNextValue(bifurcationSectionGroupId);
    bifurcationSectionBifurcationGroupIdsArray->InsertNextValue(bifurcationGroupId);
    bifurcationSectionPointArray->InsertNextTuple(averagePoint);
    bifurcationSectionNormalArray->InsertNextTuple(averageTangent);
    bifurcationSectionAreaArray->InsertNextValue(area);
    bifurcationSectionMinSizeArray->InsertNextValue(sizeRange[0]);
    bifurcationSectionMaxSizeArray->InsertNextValue(sizeRange[1]);
    bifurcationSectionShapeArray->InsertNextValue(shape);
    bifurcationSectionClosedArray->InsertNextValue(closedValue);
    bifurcationSectionOrientationArray->InsertNextValue(bifurcationSectionOrientation);
    bifurcationSectionDistanceSpheresArray->InsertNextValue(this->NumberOfDistanceSpheres);

    groupCellIds->Delete();
    cylinder->Delete();
    section->Delete();
    }

  bifurcationSectionGroupIds->Delete();
  bifurcationSectionOrientations->Delete();
}

void vtkvmtkPolyDataBifurcationSections::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


<|start_filename|>vtkVmtk/Segmentation/vtkvmtkCurvesLevelSetImageFilter.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkCurvesLevelSetImageFilter.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkCurvesLevelSetImageFilter.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkITKFilterUtilities.h"

#include "itkCurvesLevelSetImageFilter.h"

vtkStandardNewMacro(vtkvmtkCurvesLevelSetImageFilter);

vtkvmtkCurvesLevelSetImageFilter::vtkvmtkCurvesLevelSetImageFilter()
{
  this->IsoSurfaceValue = 0.0;
  this->NumberOfIterations = 100;
  this->PropagationScaling = 0.0;
  this->CurvatureScaling = 0.0;
  this->AdvectionScaling = 0.0;
  this->MaximumRMSError = 1E-4;
  this->UseNegativeFeatures = 0;
  this->UseImageSpacing = 1;
  this->AutoGenerateSpeedAdvection = 1;
  this->InterpolateSurfaceLocation = 1;
  this->DerivativeSigma = 0.0;
  this->RMSChange = 0.0;
  this->ElapsedIterations = 0;

  this->FeatureImage = NULL;
  this->SpeedImage = NULL;
}

vtkvmtkCurvesLevelSetImageFilter::~vtkvmtkCurvesLevelSetImageFilter()
{
  if (this->FeatureImage)
    {
      this->FeatureImage->Delete();
      this->FeatureImage = NULL;
    }

  if (this->SpeedImage)
    {
      this->SpeedImage->Delete();
      this->SpeedImage = NULL;
    }
}

void vtkvmtkCurvesLevelSetImageFilter::SimpleExecute(vtkImageData* input, vtkImageData* output)
{
  typedef itk::Image<float,3> ImageType;

  ImageType::Pointer inImage = ImageType::New();

  vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(input,inImage);

  ImageType::Pointer speedImage = ImageType::New();
  ImageType::Pointer featureImage = ImageType::New();

  typedef itk::CurvesLevelSetImageFilter<ImageType,ImageType> CurvesLevelSetFilterType;

  CurvesLevelSetFilterType::Pointer curvesLevelSetFilter = CurvesLevelSetFilterType::New();
  curvesLevelSetFilter->SetInput(inImage);
  curvesLevelSetFilter->SetIsoSurfaceValue(this->IsoSurfaceValue);
  curvesLevelSetFilter->SetNumberOfIterations(this->NumberOfIterations);
  curvesLevelSetFilter->SetPropagationScaling(this->PropagationScaling);
  curvesLevelSetFilter->SetCurvatureScaling(this->CurvatureScaling);
  curvesLevelSetFilter->SetAdvectionScaling(this->AdvectionScaling);
  curvesLevelSetFilter->SetMaximumRMSError(this->MaximumRMSError);
  curvesLevelSetFilter->SetUseNegativeFeatures(this->UseNegativeFeatures);
  curvesLevelSetFilter->SetUseImageSpacing(this->UseImageSpacing);
  curvesLevelSetFilter->SetAutoGenerateSpeedAdvection(this->AutoGenerateSpeedAdvection);
  curvesLevelSetFilter->SetInterpolateSurfaceLocation(this->InterpolateSurfaceLocation);
  curvesLevelSetFilter->SetDerivativeSigma(this->DerivativeSigma);
  if (this->SpeedImage)
  {
    vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(this->SpeedImage,speedImage);
    curvesLevelSetFilter->SetSpeedImage(speedImage);
  }
  if (this->FeatureImage)
  {
    vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(this->FeatureImage,featureImage);
    curvesLevelSetFilter->SetFeatureImage(featureImage);
  }
  vtkvmtkITKFilterUtilities::ConnectProgress(curvesLevelSetFilter,this);
  curvesLevelSetFilter->Update();

  this->RMSChange = curvesLevelSetFilter->GetRMSChange();
  this->ElapsedIterations = curvesLevelSetFilter->GetElapsedIterations();

  vtkvmtkITKFilterUtilities::ITKToVTKImage<ImageType>(curvesLevelSetFilter->GetOutput(),output);
}



<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/top.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*   ,d88""\   d8             888 888                                        */
/*   8888    _d88__  e88888e  888 888   o8888o  88o88o                       */
/*   `Y88b    888   d888  88b 888 888       88b 888                          */
/*    `Y88b,  888   8888oo888 888 888  o888o888 888                          */
/*      8888  888   q888      888 888 C888  888 888                          */
/*   \_o88P'  "88o"  "88oooo" 888 888  "888"888 888                          */
/*                                                                           */
/* A program for improving tetrahedral meshes, using the tetrahedral complex */
/* library provided by Starbase (see Starbase.c for details)                 */
/*                                                                           */
/* Version 1.0                                                               */
/* 18 December 2008                                                          */
/*                                                                           */
/* Copyright 2006-2008 <NAME>, all rights reserved.                  */
/*                                                                           */
/*  ======================= BSD license begins here. ======================= */
/*                                                                           */
/*  Redistribution and use in source and binary forms, with or without       */
/*  modification, are permitted provided that the following conditions are   */
/*  met:                                                                     */
/*                                                                           */
/*  - Redistributions of source code must retain the above copyright notice, */
/*    this list of conditions and the following disclaimer.                  */
/*                                                                           */
/*  - Redistributions in binary form must reproduce the above copyright      */
/*    notice, this list of conditions and the following disclaimer in the    */
/*    documentation and/or other materials provided with the distribution.   */
/*                                                                           */
/*  - Neither the name of <NAME> nor the name of the University      */
/*    of California nor the names of its contributors may be used to endorse */
/*    or promote products derived from this software without specific prior  */
/*    written permission.                                                    */
/*                                                                           */
/*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS  */
/*  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED    */
/*  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A          */
/*  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT      */
/*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    */
/*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
/*  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR   */
/*  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF   */
/*  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     */
/*  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS       */
/*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.             */
/*                                                                           */
/*  ======================== BSD license ends here. ======================== */
/*                                                                           */
/* For details on the mesh improvement techniques implemented in Stellar,    */
/* refer to the paper:                                                       */
/* "Aggressive Tetrahedral Mesh Improvement," <NAME>, <NAME>. */
/*  Shewchuk, Proceedings of the 16th International Meshing Roundtable       */
/* and the (more complete) dissertation:                                     */
/* "Tetrahedral Mesh Improvement," <NAME>,                           */
/* EECS Department, University of California, Berkeley,                      */
/* Technical Report No. UCB/EECS-2008-145                                    */
/* http://www.eecs.berkeley.edu/Pubs/TechRpts/2008/EECS-2008-145.html        */
/*****************************************************************************/

/* Include the tetrahedral complex library Starbase                          */
#include "Starbase.h"

/* for debugging assertions */
#include <assert.h>
#include <stdio.h>

/*****************************************************************************/
/*                                                                           */
/*  Defines                                                                  */
/*                                                                           */
/*****************************************************************************/
#ifndef PI
    #define PI 3.141592653589793238462643383279502884197169399375105820974944592308
#endif

/* do paranoid checks during improvement */
#define IMPROVEPARANOID false

/* verbosity of debugging output */
#define IMPROVEVERBOSITY 5

/* a really big floating point number */
#define HUGEFLOAT 1.0e100

/* the sines of some angles */
#define SINEHALF 0.00872653549837
#define SINE1  0.01745240644
#define SINE2  0.0348994967
#define SINE5  0.08715574275
#define SINE10 0.17364817767
#define SINE13 0.22495105434
#define SINE15 0.2588190451
#define SINE20 0.34202014333
#define SINE25 0.42261826174
#define SINE30 0.5
#define SINE35 0.57357643635
#define SINE40 0.64278760969
#define SINE45 0.70710678119
#define SINEEQUILATERAL 0.94280903946

/* when the journal reaches this size, half it's size (remove the older half
   of the entries) */
#define JOURNALHALFSIZE 1000000

/* vertex types */
#define INPUTVERTEX 0
#define FIXEDVERTEX 1
#define SEGMENTVERTEX 2
#define FACETVERTEX 3
#define FREEVERTEX 4
#define UNDEADVERTEX 15
/* new kind of vertex to identify the ones I've put in */
#define INSERTEDVERTEX 4

/* types of improvement passes */
#define SMOOTHPASS 0
#define TOPOPASS 1
#define CONTRACTPASS 2
#define INSERTPASS 3
#define DESPERATEPASS 4
#define DEFORMPASS 5
/* types of local improvement passes */
#define SMOOTHPASSLOCAL 6
#define TOPOPASSLOCAL 7
#define CONTRACTPASSLOCAL 8
#define INSERTPASSLOCAL 9
/* size control pass */
#define SIZECONTROLPASS 10
#define CONTRACTALLPASS 11

/* number of quality measures */
#define NUMQUALMEASURES 6

/* number of "thresholded" means used to approximate mesh quality */
#define NUMMEANTHRESHOLDS 7

/* edge cases */
#define NUMEDGECASES 10
#define NOEDGECASE 0
#define FREEFREEEDGE 1
#define FREEFACETEDGE 2
#define FREESEGMENTEDGE 3
#define FREEFIXEDEDGE 4
#define FACETFACETEDGE 5
#define FACETSEGMENTEDGE 6
#define FACETFIXEDEDGE 7
#define SEGMENTSEGMENTEDGE 8
#define SEGMENTFIXEDEDGE 9
#define FIXEDFIXEDEDGE 10

/* number of passes without improvement before static improvement quits */
#define STATICMAXPASSES 3
/* number of desperate insertion passes that can ever be attempted */
#define DESPERATEMAXPASSES 3

/*****************************************************************************/
/*  Topological improvement options                                          */
/*****************************************************************************/

/* number of tets to allow in a ring around an edge to be removed */
#define MAXRINGTETS 70
#define MAXRINGTETS2 50

/* maximum number of tets in sandwich set replacement during edge removal */
#define MAXNEWTETS 150

/* maximum number of faces in tree for multi-face removal */
#define MAXFACETREESIZE 50

/* minimum quality to allow a 4-verts-on-boundary tet to be created
   by a topological improvement operation */
#define MIN4BOUNDQUAL SINE1

/*****************************************************************************/
/*  Smoothing improvement options                                            */
/*****************************************************************************/

/* do paranoid checks of smoothing process */
#define SMOOTHPARANOID false

/* how close to the worst does a function have to be to be in the
   active set? */
#define ACTIVESETFACTOR 1.03

/* how many tets will we allow incident to one vertex for smoothing? */
#define MAXINCIDENTTETS 700

/* minimum step size */
#define MINSTEPSIZE 1.0e-5

/* maximum iterations in non-smooth line search */
#define MAXLINEITER 50

/* rate must be worse by this much to reset alpha */
#define RATEEPSILON 1.0e-6

/* maximum iterations of non smooth optimization */
#define MAXSMOOTHITER 50

/* minimum quality improvement in a smoothing step */
#define MINSMOOTHITERIMPROVE 1.0e-5

/* if d is within this of zero-length, call it zero */
#define DEPSILON 1.0e-5

/* if closest point computation has a factor smaller than this, make it the origin */
#define NEARESTMIN 1.0e-13

/* the minimum improvement of the minimum quality element for a 
   (topo|smoothing|insertion) pass to "succeed" */
#define MINMINIMPROVEMENT 1.0e-15

#define MINLOCALMEANIMPROVE 0.005

/* minimum improvement required for edge contraction to succeed */
#define MINCONTRACTIMPROVEMENT 1.0e-06

/* the dot product of two normals must be 1+- this value to be considered coplanar */
#define COPLANARTOL 1e-4

/* the absolute value of the dot product of two edges must be 1+- 
   this value to be considered colinear */
#define COLINEARTOL 1e-4

/* determines whether facet/segment vertices are smoothed */
#define SMOOTHFACETVERTICES 0x01
#define SMOOTHSEGMENTVERTICES 0x02
#define SMOOTHFIXEDVERTICES 0x04

/*****************************************************************************/
/*  Insertion/cavity improvement options                                     */
/*****************************************************************************/

/* do paranoid checks during insertion */
#define INSERTPARANOID false

/* minimum improvement for a submesh */
#define MINSUBMESHIMPROVEMENT 1.0e-3

/* maximum submesh improvement iterations */
#define MAXSUBMESHITERATIONS 8

/* if a tet is within this number of the worst tet, its close to worst */
#define CLOSETOWORST SINE2

/* how much bigger to allow the improvement stack to be when we've got 
   one of the worst tets */ 
#define TRYHARDFACTOR 15
#define TRYHARDMAXSUBMESHITERATIONS 20
#define TRYHARDMINSUBMESHIMPROVEMENT 1e-10

/* minimum quality of an intermediate tet */
#define MINTETQUALITY 1.0e-14
#define MINSIZETETQUALITY 1.0e-10

/* maximum size of stuff for cavity drilling */
#define MAXCAVITYFACES 10000
#define MAXCAVITYTETS 10000

/* minimum improvement of vertex insertion */
#define MININSERTIONIMPROVEMENT 1.0e-13

/* minimum positivity of orientation for a face to be oriented "toward" */
#define MINFACING 1.0e-7

/* factor by which child cavity qualities are increased */
#define CHILDFAVORFACTOR 1.0

/* maximum difference between two qualities where they are considered 'equal' */
#define MAXQUALDIFFERENCE 1.0e-15

/* maximum number of outgoing faces allowed for a tet */
#define MAXOUTFACES 200

/* maximum number of edges in a cavity dag */
#define MAXCAVITYDAGEDGES 50000

/* perform initial/final smooth of all cavity vertices */
#define INITIALCAVITYSMOOTH true
#define FINALCAVITYSMOOTH true

/* maximum stack size for cavity improvement */
#define MAXCAVITYSTACK 250

/* biggest size for cavity heap */ 
#define MAXCAVITYHEAPSIZE MAXCAVITYTETS

/* deepest level a tet can be */
#define MAXCAVDEPTH 1000

/* failure count on which to perform desperate insertion pass */
#define DESPERATEPASSNUM 2
/* if the quality of the mesh is really terrible, don't bother trying to insert 
   up to max insert quality */
#define QUALFROMDESPERATE SINE15
/* if the minimum quality is high, reach even higher by this much in desperate pass */
#define QUALUPFROMDESPERATE SINE1

/* never attempt insertion on more than this many tets, no matter what */
#define MAXINSERTTETS 4000

/*****************************************************************************/
/*  size control options                                                     */
/*****************************************************************************/

/* minimum quality of affect tets after size-control edge contraction */
#define MINCONTRACTQUAL 5.0e-2
#define MINSIZESPLITQUAL 5.0e-2
#define MEANEDGESCALE 0.8
/* maximum number of size control iterations */
/*#define MAXSIZEITERS 30*/
#define MAXSIZEITERS 10
#define CONTROLSHORTFAC 1.35
#define CONTROLLONGFAC 0.85

/*****************************************************************************/
/*                                                                           */
/*  Data structures                                                          */
/*                                                                           */
/*****************************************************************************/

/* structure to hold all the options for improvement */
struct improvebehavior
{
    /* Quality measure */
    int qualmeasure;             /* quality measure used */
    starreal sinewarpfactor;     /* warp obtuse sines by this factor */
    
    /* Quadric smoothing options */
    int usequadrics;             /* incorporate quadric error into the objective function */
    starreal quadricoffset;      /* quality to start every quadric at */
    starreal quadricscale;       /* factor to scale quadric by */
    
    /* Smoothing options */
    int nonsmooth;               /* enable non-smooth optimization-based smoothing */
    int facetsmooth;             /* enable smoothing of facet vertices */
    int segmentsmooth;           /* enable smoothing of segment vertices */
    int fixedsmooth;             /* enable smoothing of fixed vertices */
    
    /* Topological options */
    int edgeremoval;             /* enable edge removal */
    int edgecontraction;         /* enable edge contraction */
    int boundedgeremoval;        /* enable boundary edge removal */
    int singlefaceremoval;       /* enable single face removal (2-3 flips) */
    int multifaceremoval;        /* enable multi face removal */
    int flip22;                  /* enable 2-2 flips */
    int jflips;                  /* use Jonathan's faster flip routines */
    
    /* Insertion options */
    int enableinsert;            /* global enable of insertion */
    starreal insertthreshold;    /* percent worst tets */
    int insertbody;              /* enable body vertex insertion */
    int insertfacet;             /* enable facet insertion */
    int insertsegment;           /* enablem segment insertion */
    int cavityconsiderdeleted;   /* consider enlarging cavity for deleted tets? */
    int cavdepthlimit;           /* only allow initial cavity to includes tets this deep */
    
    /* anisotropic meshing options */
    int anisotropic;             /* globally enable space warping with deformation tensor */
    int tensor;                  /* which scaling tensor field to use */
    int tensorb;                 /* second tensor, to blend with the first one */
    starreal tensorblend;  /* between 0 and 1, how much of anisotropy to use */
    
    /* sizing options */
    int sizing;                  /* globally enable mesh element size control */
    int sizingpass;              /* enable or disable initial edge length control */
    starreal targetedgelength;   /* edge length of the ideal edge for this mesh */
    starreal longerfactor;       /* factor by which an edge can be longer */
    starreal shorterfactor;      /* factor by which an edge can be shorter */
    
    /* Dynamic improvement options */
    starreal dynminqual;         /* minimum quality demanded for dynamic improvement. */
    starreal dynimproveto;       /* after minimum quality is reached, improve to at least this level */
    int deformtype;              /* which fake deformation to use */
    int dynimprove;              /* perform dynamic improvement with fake deformation? */
    
    /* thresholds */
    starreal minstepimprovement; /* demand at least this much improvement in the mean per step */
    starreal mininsertionimprovement; /* demand in improvement for insertion */
    starreal maxinsertquality[NUMQUALMEASURES];   /* never attempt insertion in a tet better than this */
    
    /* improvement limits */
    starreal goalanglemin;       /* stop improvement if smallest angle reaches this threshold */
    starreal goalanglemax;       /* stop improvement if largest angle reaches this threshold */
    
    /* quality file output */
    int minsineout;              /* en/disable .minsine file output */
    int minangout;               /* en/disable .minang file output */
    int maxangout;               /* en/disable .maxang file output */
    int vlrmsout;                /* en/disable .vlrms file output */
    int nrrout;                 /* en/disable .rnrr file output */
    
    /* output file name prefix */
    char fileprefix[100];
    
    /* enable animation */
    int animate;
    /* for animation, only output .stats */
    int timeseries;
    
    /* verbosity */
    int verbosity;
    int usecolor;
    
    /* miscellaneous */
    int outputandquit;           /* just produce all output files for unchanged mesh */
};

/* structure to hold global improvement statistics */
struct improvestats
{
    /* smoothing stats */
    int nonsmoothattempts;
    int nonsmoothsuccesses;
    int freesmoothattempts;
    int freesmoothsuccesses;
    int facetsmoothattempts;
    int facetsmoothsuccesses;
    int segmentsmoothattempts;
    int segmentsmoothsuccesses;
    int fixedsmoothattempts;
    int fixedsmoothsuccesses;
    
    /* topological stats */
    int edgeremovals;
    int boundaryedgeremovals;
    int edgeremovalattempts;
    int boundaryedgeremovalattempts;
    int ringsizesuccess[MAXRINGTETS];
    int ringsizeattempts[MAXRINGTETS];
    int faceremovals;
    int faceremovalattempts;
    int facesizesuccess[MAXFACETREESIZE];
    int facesizeattempts[MAXFACETREESIZE];
    int flip22attempts;
    int flip22successes;
    int edgecontractionattempts;
    int edgecontractions;
    int edgecontractcaseatt[NUMEDGECASES+1];
    int edgecontractcasesuc[NUMEDGECASES+1];
    int edgecontractringatt[MAXRINGTETS];
    int edgecontractringsuc[MAXRINGTETS];
    
    /* insertion stats */
    int bodyinsertattempts;
    int bodyinsertsuccesses;
    int facetinsertattempts;
    int facetinsertsuccesses;
    int segmentinsertattempts;
    int segmentinsertsuccesses;
    int maxcavitysizes[MAXCAVITYTETS];
    int finalcavitysizes[MAXCAVITYTETS];
    int biggestcavdepths[MAXCAVDEPTH];
    int lexmaxcavdepths[MAXCAVDEPTH];
    
    /* timing stats */
#ifndef NO_TIMER
    struct timeval starttime;
#endif /* not NO_TIMER */
    int totalmsec;
    int smoothmsec;
    int topomsec;
    int contractmsec;
    int insertmsec;
    int smoothlocalmsec;
    int topolocalmsec;
    int insertlocalmsec;
    int contractlocalmsec;
    int biggestcavityusec;
    int finalcavityusec;
    int cavityimproveusec;
    
    /* general stats */
    int startnumtets;
    int finishnumtets;
    int startnumverts;
    int finishnumverts;
    starreal dynchangedvol;
    
    /* quality stats */
    starreal finishworstqual;
    starreal startworstqual;
    starreal startminangle;
    starreal startmaxangle;
    starreal startmeanquals[NUMMEANTHRESHOLDS];
    starreal finishmeanquals[NUMMEANTHRESHOLDS];
};

/* a tet for the improvement stack, referred to by the tuple of its vertices
   and a single quality measure */
struct improvetet
{
    tag verts[4];
    starreal quality;
};

/* structure for holding quality and gradient information for non-smooth
   optimization-based vertex smoothing */
struct opttet
{
    tag verts[4];             /* vertices of the tetrahedron */
    starreal volume;            /* volume of tetrahedron */
    starreal volumegrad[3];     /* the gradient of the volume of the tet wrt vtx1 */
    starreal sine[6];           /* sine of each dihedral angle of the tet */
    starreal sinegrad[6][3];    /* gradient of each sine */
    starreal rnrr;              /* root normalized radius ratio */
    starreal rnrrgrad[3];       /* gradient of root normalized radius ratio */
    starreal vlrms3r;           /* V / lrms^3 ratio */
    starreal vlrms3rgrad[3];    /* gradient thereof */
    starreal edgelength[3][4];  /* the lengths of each of the edges of the tet */
    starreal edgegrad[3][4][3]; /* the gradient of each edge length wrt vtx1 */
    starreal facearea[4];       /* areas of the faces of the tet */
    starreal facegrad[4][3];    /* the gradient of each of the face areas wrt vtx1 */
};

typedef enum {false, true} bool;

/* store mappings from tags to vertex types */
struct vertextype
{
    int kind;        /* the kind of vector this is (FREEVERTEX, FACETVERTEX, etc) */
    starreal vec[3]; /* a vector associated with the vertex. for FACETVERTEX,
                        this is the normal to the plane that the vertex can move in.
                        for SEGMENTVERTEX, this is a vector in the direction of the
                        segment. */
};

/* stack data structure using arraypool */

/* cardinal value for empty stack */
#define STACKEMPTY -1

/* use 1024 tets per level-two block */
#define LOG2TETSPERSTACKBLOCK 10

/* a stack implemented with an arraypool */
struct arraypoolstack
{
    struct arraypool pool; /* the array pool that makes up the stack */
    long top;     /* the index of the top element in the array */
    long maxtop;  /* the maximum size the stack has ever been */
};

/* surface error quadric */
struct quadric
{
    starreal a2, ab, ac, ad;
    starreal     b2, bc, bd;
    starreal         c2, cd;
    starreal             d2;
    starreal origpos[3];     /* original vertex position */
    int numfaces;            /* number of incident faces */
    starreal facesum;        /* sum of incident face areas */
    starreal edge2harm;      /* harmonic mean of squares of inc. edge lengths */
    bool hasquadric;
};

/*****************************************************************************/
/*                                                                           */
/*  Global variables                                                         */
/*                                                                           */
/*****************************************************************************/

/* global behavior struct */
struct behavior behave;

/* global improvement behavior struct */
struct improvebehavior improvebehave;

/* global statistics */
struct improvestats stats;

/* global vertex info */
struct arraypool vertexinfo;

/* global vertex pool */
struct proxipool *vertexpoolptr;

/* global surface vertex quadrics */
struct arraypool surfacequadrics;

/* counter for journal IDs */
int maxjournalid = 1;

/* types of quality measures that may be used */
enum tetqualitymetrics
{
    QUALMINSINE,
    QUALRADIUSRATIO,
    QUALVLRMS3RATIO,
    QUALMEANSINE,
    QUALMINSINEANDEDGERATIO,
    QUALWARPEDMINSINE,
    QUALMINANGLE,
    QUALMAXANGLE
};

/* types of anisotropic sizing fields */
enum tensorfields
{
    NOTENSOR,
    STRETCHX,
    STRETCHY,
    SINK,
    SWIRL,
    CENTER,
    PERIMETER,
    RIGHT,
    SINE,
    STRAIN
};

/* types of artificial deformation functions */
enum deformtypes
{
    TWIST,
    STRETCH,
    SQUISHMIDDLE
};

/* quality thresholds for averages */
starreal meanthresholds[NUMQUALMEASURES][NUMMEANTHRESHOLDS] =
{
    /* QUALMINSINE thresholds */
    {
        SINE1,
        SINE5,
        SINE10,
        SINE15,
        SINE25,
        SINE35,
        SINE45
    },
    /* QUALRADIUSRATIO thresholds */
    {
        0.1,
        0.2,
        0.3,
        0.4,
        0.5,
        0.6,
        0.7
    },
    /* QUALVLRMS3RATIO thresholds */
    {
        0.1,
        0.2,
        0.3,
        0.4,
        0.5,
        0.6,
        0.7
    },
    /* QUALMEANSINE thresholds */
    {
        SINE1,
        SINE5,
        SINE10,
        SINE15,
        SINE25,
        SINE35,
        SINE45
    },
    /* QUALMINSINEANDEDGERATIO thresholds */
    {
        SINE1,
        SINE5,
        SINE10,
        SINE15,
        SINE25,
        SINE35,
        SINE45
    },
    /* QUALWARPEDMINSINE thresholds */
    {
        SINE1,
        SINE5,
        SINE10,
        SINE15,
        SINE25,
        SINE35,
        SINE45
    }
};

int meanthresholdangles[NUMMEANTHRESHOLDS] =
{
    1,
    5,
    10,
    15,
    25,
    35,
    45
};

int globalvertexcount;

/* bounding box for the mesh */
starreal G_boundingbox[6];
starreal G_center[3];
starreal G_range[3];

/*****************************************************************************/
/* Shared function declarations                                              */
/*****************************************************************************/

/* TODO should these really be in header files? what a pain... */

/* topological.c */
void inserttet(struct tetcomplex *mesh,
               tag vtx1,
               tag vtx2,
               tag vtx3,
               tag vtx4,
               bool record);
void deletetet(struct tetcomplex *mesh,
               tag vtx1,
               tag vtx2,
               tag vtx3,
               tag vtx4,
               bool record);
void flip23(struct tetcomplex *mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtxbot,
            tag vtxtop,
            bool record);
void flip22(struct tetcomplex *mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtxbot,
            tag vtxtop,
            bool record);
void flip32(struct tetcomplex *mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtxbot,
            tag vtxtop,
            bool record);
void flip13(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag facetvtx,
            bool record);
void flip31(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag facetvtx,
            bool record);
void flip12(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag segmentvtx,
            bool record);
void flip21(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag segmentvtx,
            bool record);
void flip14(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag facetvtx,
            bool record);
void flip41(struct tetcomplex* mesh,
            tag vtx1,
            tag vtx2,
            tag vtx3,
            tag vtx4,
            tag facetvtx,
            bool record);

/* size.c */
void sizereportstream(FILE *o, struct tetcomplex *mesh);

/* print.c */
void printtetverts(struct tetcomplex *mesh, tag *tet);
void printtetvertssep(struct tetcomplex *mesh,
                      tag vtx1,
                      tag vtx2,
                      tag vtx3,
                      tag vtx4);

/* journal.c */
void findtetfromvertex(tetcomplex *mesh,
                       tag vtx,
                       tag outtet[4]);
                       
/* arraypoolstack.c */
void stackinit(struct arraypoolstack *stack, arraypoolulong objectbytes);
void stackrestart(struct arraypoolstack *stack);
void stackdeinit(struct arraypoolstack *stack);
void* stackpush(struct arraypoolstack *stack);
void* stackpop(struct arraypoolstack *stack);
void fillstackqual(struct tetcomplex *mesh,
                   struct arraypoolstack *stack,
                   int qualmeasure,
                   starreal threshold,
                   starreal *meanqual,
                   starreal *minqual);
                   
/* pointer to strain thing from Nutt's sim */
double (*G_evalstrain)(const double* point);

/*****************************************************************************/
/*                                                                           */
/*  Convenience functions                                                    */
/*                                                                           */
/*****************************************************************************/

int mytetcomplexconsistency(struct tetcomplex *plex) {
 struct tetcomplexposition pos;
 tag nexttet[4];
 arraypoolulong horrors;

 horrors = 0;
 tetcomplexiteratorinit(plex, &pos);
 tetcomplexiterateall(&pos, nexttet);
 while (nexttet[0] != STOP) {
   horrors += tetcomplexmissingtet(plex, nexttet[0], nexttet[2],
                                    nexttet[3], nexttet[1]);
   horrors += tetcomplexmissingtet(plex, nexttet[0], nexttet[3],
                                    nexttet[1], nexttet[2]);
   horrors += tetcomplexmissingtet(plex, nexttet[1], nexttet[2],
                                    nexttet[0], nexttet[3]);
   horrors += tetcomplexmissingtet(plex, nexttet[1], nexttet[3],
                                    nexttet[2], nexttet[0]);
   horrors += tetcomplexmissingtet(plex, nexttet[2], nexttet[3],
                                    nexttet[0], nexttet[1]);
   tetcomplexiterateall(&pos, nexttet);
 }

 /*if (horrors == 0) {
     printf("  Tremble before my vast wisdom, with which "
            "I find the mesh to be consistent.\n");
 } else if (horrors == 1) {
   printf("  !! !! !! !! Precisely one oozing cyst sighted.\n");
 } else {
   printf("  !! !! !! !! %d monstrosities witnessed.\n", horrors);
 }*/
 if (horrors == 0)
 {
     return 1;
 }
 else
 {
     return 0;
 }
}

/* copy the values from one array of tags to the other */
void tagarraycopy(tag A1[],
                  tag A2[],
                  int length)
{
    memcpy(A2, A1, sizeof(tag)*length);
}

/* copy the values from one array of points to the other */
void pointarraycopy(starreal A1[][3],
                    starreal A2[][3],
                    int length)
{
    memcpy(A2, A1, sizeof(starreal)*3*length);
}

/* function to sort the vertices of a tet */
#define swaptag(x, y) do {tag tmp; tmp = x; x = y; y = tmp; } while (0)
void sorttetverts(tag tet[4])
{
    if (tet[1] < tet[0]) swaptag(tet[1], tet[0]);
    if (tet[2] < tet[1]) swaptag(tet[2], tet[1]);
    if (tet[3] < tet[2]) swaptag(tet[3], tet[2]);
    if (tet[1] < tet[0]) swaptag(tet[1], tet[0]);
    if (tet[2] < tet[1]) swaptag(tet[2], tet[1]);
    if (tet[1] < tet[0]) swaptag(tet[1], tet[0]);
}

/* Compute the parity of the permutation of the array perm.
   The array should be length long, and contain integers from
   0 up to length -1. The even/oddness is in relation to the
   permutation frem 0...length-1, in order. It returns 0 if 
   perm is an even permutation, and 1 if it is odd */
int permutationparity(int *perm, int length)
{
    int inversions = 0; /* number of inversions */
    int i,j;            /* loop indices */
    
    for (i=0; i<length-1; i++)
    {
        for (j=i+1; j<length; j++)
        {
            /* check if i < j AND p(i) > p(j). If so, inversion */
            if (perm[i] > perm[j])
            {
                inversions++;
            }
        }
    }
    
    /* if there are an odd number of inversions, odd parity */
    return inversions % 2;
}

/* a new, faster way to test tet equivalence ? */
bool sametet(tag v11, tag v12, tag v13, tag v14,
             tag v21, tag v22, tag v23, tag v24)
{
    /* we just need to verify that every vertex in tet one is in
       tet two */
    if (
         (v11 == v21 || v11 == v22 || v11 == v23 || v11 == v24) &&
         (v12 == v21 || v12 == v22 || v12 == v23 || v12 == v24) &&
         (v13 == v21 || v13 == v22 || v13 == v23 || v13 == v24) &&
         (v14 == v21 || v14 == v22 || v14 == v23 || v14 == v24)
       )
    {
        return true;
    }
    return false;
}

/* tests whether the two tetrahedra are the same,
   where "sameness" is gauged by whether they share
   all the same vertices, and the orientation is the same.
   orientation being the same means that the order of the
   vertices of one is an even permutation of the other */
bool oldsametet(tag vtx11, tag vtx12, tag vtx13, tag vtx14,
             tag vtx21, tag vtx22, tag vtx23, tag vtx24)
{
    tag tet1sorted[4];
    tag tet2sorted[4];
    
    tet1sorted[0] = vtx11;
    tet1sorted[1] = vtx12;
    tet1sorted[2] = vtx13;
    tet1sorted[3] = vtx14;
    
    tet2sorted[0] = vtx21;
    tet2sorted[1] = vtx22;
    tet2sorted[2] = vtx23;
    tet2sorted[3] = vtx24;
    
    /* sort the vertices of each tet */
    sorttetverts(tet1sorted);
    sorttetverts(tet2sorted);
    
    /* make sure they both have the same vertices */
    if ( 
         (tet1sorted[0] != tet2sorted[0]) ||
         (tet1sorted[1] != tet2sorted[1]) ||
         (tet1sorted[2] != tet2sorted[2]) ||
         (tet1sorted[3] != tet2sorted[3])
       )
    {
        return false;
    }
    
    /* the rest is unnecessary because same verts but different
       parity implies that one of the tets is invalid anyway */
    return true;
}

/* determine of two sets of three tags represent
   the same oriented face, meaning that they have the
   same vertices and that the vertices come in the same
   order, with wrapping allowed. So (1,2,3) = (3,1,2). */
bool sameface(tag f11, tag f12, tag f13,
              tag f21, tag f22, tag f23)
{
    /* for speed, explicitly check all three possible 
       situations where the two faces are equal */
    if (
            ((f11 == f21) && (f12 == f22) && (f13 == f23)) ||
            ((f11 == f22) && (f12 == f23) && (f13 == f21)) ||
            ((f11 == f23) && (f12 == f21) && (f13 == f22))
       )
    {
        return true;
    }
    return false;
}

/* check whether the specified tet exists in the mesh. if it does, return 1.
   otherwise, return 0 */
int tetexists(struct tetcomplex *mesh, tag vtx1, tag vtx2, tag vtx3, tag vtx4)
{
    tag topbot[2];
    int foundface;
    int horrors = 0;
    
    foundface = tetcomplexadjacencies(mesh, vtx2, vtx3, vtx4, topbot);
    if (foundface == 0)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("tet doesn't exist because face (%d %d %d) isn't found...\n", (int) vtx2, (int) vtx3, (int) vtx4);
        }
        return 0;
    }
    /* face was found... is top vertex correct? */
    if (topbot[0] != vtx1)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("tet doesn't exist because top vertex doesn't match...\n");
        }
        return 0;
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("verified that tet with verts %d %d %d %d exists in mesh\n", (int) vtx1, (int) vtx2, (int) vtx3, (int) vtx4);
        printf("face %d %d %d was found and the vert opposite it was %d\n", (int) vtx2, (int) vtx3, (int) vtx4, (int) topbot[0]);
    }
    
    /* taken from tetcomplexconsistency(), except just checks one tet */
    if (IMPROVEPARANOID)
    {
        horrors += tetcomplexmissingtet(mesh, vtx1, vtx3,
                                         vtx4, vtx2);
        horrors += tetcomplexmissingtet(mesh, vtx1, vtx4,
                                         vtx2, vtx3);
        horrors += tetcomplexmissingtet(mesh, vtx2, vtx3,
                                         vtx1, vtx4);
        horrors += tetcomplexmissingtet(mesh, vtx2, vtx4,
                                         vtx3, vtx1);
        horrors += tetcomplexmissingtet(mesh, vtx3, vtx4,
                                         vtx1, vtx2);
    
        if (horrors != 0)
        {
            printf("everything was cool with your check but horrors != 0...\n");
            return 0;
        }
    }
    
    return 1;
}

/* wrapper for checking tet existence with an array */
int tetexistsa(tetcomplex *mesh, tag tet[4])
{
    return tetexists(mesh, tet[0], tet[1], tet[2], tet[3]);
}

/* get all the tets incident on vtx1 which is in the tet 
   (vtx1, vtx2, vtx3, vtx4). This function is recursive and
   should first be called with numincident = 0.
   return 0 if the number of incident tets exceed the
   maximum allowed. Set boundary flag if vertex lies on
   boundary (i.e., has at least one ghost tet incident) */
int getincidenttets(struct tetcomplex *mesh,
                    tag vtx1,
                    tag vtx2,
                    tag vtx3,
                    tag vtx4,
                    tag incidenttets[][4],
                    int *numincident,
                    bool *noghostflag)
{
    tag neightets[3][4];  /* neighbor tetrahedra */
    tag topbot[2];        /* the top and bottom vertices from adjacency query */
    int foundface;        /* checks whether adjacency query finds the face at all */
    tag neighfaces[3][4]; /* the three faces we want to check, last vertex is leftover */
    int i,j;              /* loop indices */
    bool visited = false; /* whether each neighbor has been visited */
    tag i2, i3, i4;       /* incident tet vertices, excluding central vertex */
    tag n2, n3, n4;       /* neighbor tet vertices, excluding central vertex */
    
    /* first, check to make sure this tet still exists in the mesh */
    if (tetexists(mesh, vtx1, vtx2, vtx3, vtx4) == 0)
    {
        return 0;
    }
    
    /* add the this tet to the list of incident tets */
    incidenttets[*numincident][0] = vtx1;
    incidenttets[*numincident][1] = vtx2;
    incidenttets[*numincident][2] = vtx3;
    incidenttets[*numincident][3] = vtx4;
    *numincident = (*numincident) + 1;
    
    /* check to make sure we aren't going crazy */
    if (*numincident > MAXINCIDENTTETS)
    {
        printf("when finding incident tets, exceeded %d tets, giving up\n", MAXINCIDENTTETS);
        return 0;
    }
    
    /* the three neighbor tets to this one that are also
       incident on vtx1 can be found using adjacency queries
       on the faces:
       
       (vtx1, vxt2, vtx3),
       (vtx1, vtx4, vtx2), and
       (vtx1, vtx3, vtx4).
       
       the "top" vertices from these queries will be apexes
       of the three adjoining tetrahedra. the "bottom" vertices
       will be the fourth vertex of the current tetrahedron.
    */
    neighfaces[0][0] = vtx1;
    neighfaces[0][1] = vtx2;
    neighfaces[0][2] = vtx3;
    neighfaces[0][3] = vtx4; /* should be the bottom vertex in adj query */
    
    neighfaces[1][0] = vtx1;
    neighfaces[1][1] = vtx4;
    neighfaces[1][2] = vtx2;
    neighfaces[1][3] = vtx3; /* should be the bottom vertex in adj query */
    
    neighfaces[2][0] = vtx1;
    neighfaces[2][1] = vtx3;
    neighfaces[2][2] = vtx4;
    neighfaces[2][3] = vtx2; /* should be the bottom vertex in adj query */
    
    /* for each neighbor face */
    for (i=0; i<3; i++)
    {
        /* make sure the original tet exists from this perspective */
        assert(tetexists(mesh,
                         neighfaces[i][3],
                         neighfaces[i][0],
                         neighfaces[i][2],
                         neighfaces[i][1]));

        foundface = tetcomplexadjacencies(mesh, 
                                          neighfaces[i][0], 
                                          neighfaces[i][1], 
                                          neighfaces[i][2], 
                                          topbot);
                                      
        /* check that the face was found */
        assert(foundface == 1);

        /* if any tet adjacent to this vertex is a ghost tet,
           set the boundary flag */
        if (topbot[0] == GHOSTVERTEX)
        {
            *noghostflag = false;
        }

        /* the bottom vertex was the other vertex in the tet */
        assert(topbot[1] == neighfaces[i][3]);
    
        
        /* otherwise, we've got a neighbor tet. To keep same vertex as vtx1,
           save this tet as (neigh[0], neigh[1], top, neigh[2].  */
        neightets[i][0] = neighfaces[i][0];
        neightets[i][1] = neighfaces[i][1];
        neightets[i][2] = topbot[0];
        neightets[i][3] = neighfaces[i][2];
        
    }
    
    /* now, figure out which neighbors we've visited */
    
    /* for each neighbor tet */
    for (i=0; i<3; i++)
    {
        /* if this neighbor tet is a ghost tet, no need to visit */
        if (neightets[i][2] == GHOSTVERTEX)
        {
            visited = true;
        }
        else
        {
            visited = false;
        
            /* get the vertices of this neighbor tet, excluding central vertex */
            n2 = neightets[i][1];
            n3 = neightets[i][2];
            n4 = neightets[i][3];
        
            /* for each tet visited so far */
            for (j=0; j<*numincident; j++)
            {
                /* get the vertices of this tet, excluding central vertex */
                i2 = incidenttets[j][1];
                i3 = incidenttets[j][2];
                i4 = incidenttets[j][3];
            
                /* is this tet the same as the current neighbor tet? */
                /* because we know that all of the tets have the same first
                   vertex (the one we're find incident elements for), all
                   we need to check whether the face vertices are the same,
                   and that they come in the same order (wrapping allowed).
                   This means that face (3,2,1) is the same as face (1,3,2) */
                if (sameface(n2,n3,n4, i2,i3,i4))
                {
                    /* then mark this neighbor as visited and don't check any more */
                    visited = true;
                    break;
                } 
            }
        }
        
        /* if it hasn't been visited */
        if (visited != true)
        {
            /* find incident tets using DFS on it */
            getincidenttets(mesh, 
                            neightets[i][0], 
                            neightets[i][1], 
                            neightets[i][2],
                            neightets[i][3],
                            incidenttets,
                            numincident,
                            noghostflag);
        }
    }
    
    return 1;
}

/* returns true if the tet (1,2,3,4) has
   positive orientation, and false otherwise */
bool positivetet(tetcomplex *mesh,
                 tag v1,
                 tag v2,
                 tag v3,
                 tag v4)
{
    return (orient3d(&behave,
                    ((struct vertex *) tetcomplextag2vertex(mesh, v1))->coord,
                    ((struct vertex *) tetcomplextag2vertex(mesh, v2))->coord,
                    ((struct vertex *) tetcomplextag2vertex(mesh, v3))->coord,
                    ((struct vertex *) tetcomplextag2vertex(mesh, v4))->coord) > 0);
}

/* convert from a sin of an angle to that angle in degrees (does not test obtuseness) */
starreal sintodeg(starreal insine)
{
    return asin(insine) * 180.0 / PI;
}

/* convert from an angle in degrees to sin */
starreal degtosin(starreal inangle)
{
    return sin((inangle) * (PI / 180.0));
}

starreal tantodeg(starreal intan)
{
    return atan(intan) * 180.0 / PI;
}

starreal radtodeg(starreal inangle)
{
    return (inangle * 180) / PI;
}

/* for printing color in output to the screen */
#define RESET		0
#define BRIGHT 		1
#define DIM         2
#define UNDERLINE 	3
#define BLINK		4
#define REVERSE		7
#define HIDDEN		8

#define BLACK 		0
#define RED		    1
#define GREEN		2
#define YELLOW		3
#define BLUE		4
#define MAGENTA		5
#define CYAN		6
#define	WHITE		7

void textcolor(int attr, int fg, int bg)
{	char command[13];

	/* Command is the control command to the terminal */
	if (improvebehave.usecolor == true)
	{
	    sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40);
	    printf("%s", command);
	}
}

/* zero out the stats structure */
void initimprovestats(void)
{
    memset(&stats, 0, sizeof(struct improvestats));
}

int countverts(struct proxipool *vertpool)
{
    tag vertextag;
    int numverts = 0;
    vertextag = proxipooliterate(vertpool, NOTATAG);
    
    while (vertextag != NOTATAG)
    {
        numverts++;
        vertextag = proxipooliterate(vertpool, vertextag);
    }
    
    return numverts;
}

int counttets(struct tetcomplex *mesh)
{
    struct tetcomplexposition pos; /* position of iterator in the mesh */
    tag tet[4];
    int numtets = 1;
    
    /* initialize the iterator over the mesh */
    tetcomplexiteratorinit(mesh, &pos);
    /* retrieve the first tet in the mesh */
    tetcomplexiteratenoghosts(&pos, tet);
    
    /* for each tet */
    while (tet[0] != STOP) 
    {
        numtets++;
        tetcomplexiteratenoghosts(&pos, tet);
    }
    return numtets;
}

#ifndef NO_TIMER
/* returns the number of milliseconds elapsed between tv1 and tv2 */
int msecelapsed(struct timeval tv1, struct timeval tv2)
{
    return 1000l * (tv2.tv_sec - tv1.tv_sec) + (tv2.tv_usec - tv1.tv_usec) / 1000l;
}

/* returns the number of microseconds elapsed between tv1 and tv2 */
int usecelapsed(struct timeval tv1, struct timeval tv2)
{
    return 1000000l * (tv2.tv_sec - tv1.tv_sec) + (tv2.tv_usec - tv1.tv_usec);
}
#endif /* not NO_TIMER */

/* print out quality, adjusting to current quality measure */
starreal pq(starreal qual)
{
    if (improvebehave.qualmeasure == QUALMINSINE ||
        improvebehave.qualmeasure == QUALWARPEDMINSINE)
    {
        return sintodeg(qual);
    }
    return qual;
}


/* compute the rectangular bounding box for mesh vertices, so deformation and
   anisotropy can use normalized coordinates */
void setboundingbox(tetcomplex *mesh)
{
    starreal *v;
    tag iterator;
    
    G_boundingbox[0] = HUGEFLOAT;
    G_boundingbox[1] = HUGEFLOAT;
    G_boundingbox[2] = HUGEFLOAT;
    G_boundingbox[3] = -HUGEFLOAT;
    G_boundingbox[4] = -HUGEFLOAT;
    G_boundingbox[5] = -HUGEFLOAT;
    
    if (improvebehave.verbosity > 4)
    {
        printf("Computing mesh bounding box...\n");
    }
    
    /* loop over each mesh vertex, looking for extreme values */
    iterator = proxipooliterate(mesh->vertexpool, NOTATAG);
    while (iterator != NOTATAG) 
    {
        v = ((struct vertex *) proxipooltag2object(mesh->vertexpool, iterator))->coord;
        
        if (v[0] < G_boundingbox[0]) G_boundingbox[0] = v[0];
        if (v[1] < G_boundingbox[1]) G_boundingbox[1] = v[1];
        if (v[2] < G_boundingbox[2]) G_boundingbox[2] = v[2];
        if (v[0] > G_boundingbox[3]) G_boundingbox[3] = v[0];
        if (v[1] > G_boundingbox[4]) G_boundingbox[4] = v[1];
        if (v[2] > G_boundingbox[5]) G_boundingbox[5] = v[2];
        
        iterator = proxipooliterate(mesh->vertexpool, iterator);
    }
    
    /* set the range and center for each coordinate, for vertex normalization */
    G_range[0] = G_boundingbox[3] - G_boundingbox[0];
    G_range[1] = G_boundingbox[4] - G_boundingbox[1];
    G_range[2] = G_boundingbox[5] - G_boundingbox[2];
    G_center[0] = (G_boundingbox[3] + G_boundingbox[0]) / 2.0;
    G_center[1] = (G_boundingbox[4] + G_boundingbox[1]) / 2.0;
    G_center[2] = (G_boundingbox[5] + G_boundingbox[2]) / 2.0;    
    
    if (improvebehave.verbosity > 4)
    {
        printf("min corner [%g %g %g], max corner [%g %g %g]\n", G_boundingbox[0], G_boundingbox[1], G_boundingbox[2], G_boundingbox[3], G_boundingbox[4], G_boundingbox[5]);
        printf("ranges = [%g %g %g], center = [%g %g %g]\n", G_range[0], G_range[1], G_range[2], G_center[0], G_center[1], G_center[2]);
    }
}


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/size.c<|end_filename|>
/* size control functions */

/* compute statistics about tetrahedra volumes */
void volumestats(struct tetcomplex *mesh,
                 starreal *minvol,
                 starreal *maxvol,
                 starreal *meanvol)
{
    struct tetcomplexposition pos; /* position of iterator in the mesh */
    tag tet[4];                    /* the current tet */
    starreal volume;               /* the volume of the current tet */
    int numtets = 0;               /* number of tets in the mesh */
    
    *minvol = HUGEFLOAT;
    *maxvol = 0.0;
    *meanvol = 0.0;
    
    /* initialize the iterator over the mesh */
    tetcomplexiteratorinit(mesh, &pos);
    /* retrieve the first tet in the mesh */
    tetcomplexiteratenoghosts(&pos, tet);
    
    /* for each tet */
    while (tet[0] != STOP) 
    {
        /* compute the quality of this tet */
        volume = tetvolume(mesh, tet[0], tet[1], tet[2], tet[3]);
        
        /* keep track of minimum, maximum and average volume */
        if (volume < *minvol) *minvol = volume;
        if (volume > *maxvol) *maxvol = volume;
        *meanvol += volume;
        
        /* fetch the next tet from the mesh */
        tetcomplexiteratenoghosts(&pos, tet);
        numtets++;
    }
    assert(numtets != 0);
    assert(*meanvol > 0.0);
    assert(*minvol > 0.0);
    
    /* compute average */
    *meanvol /= numtets;
}

/* compute statistics about edge lengths in the mesh */
void edgelengthstats(struct tetcomplex *mesh,
                     starreal *minedge,
                     starreal *maxedge,
                     starreal *meanedge,
                     starreal *medianedge,
                     bool anisotropic)
{
    struct tetcomplexposition pos; /* position of iterator in the mesh */
    tag tet[4];                    /* the current tet */
    int numedges = 0;              /* number of edges in the mesh */
    tag adjacencies[2];
    tag origin;
    tag destin;
    tag apex;
    tag stopvtx;
    tag searchvtx = NOTATAG;
    tag swaptag;
    int writeflag = 0;
    int i;
    starreal edge[3];
    starreal edgelength;
    starreal origcoord[3];
    starreal destcoord[3];
    starreal E[3][3];
    
    /* a hack: store edge lengths in a tet stack to compute median */
    struct arraypoolstack edgestack;
    struct improvetet *edgetet;
    stackinit(&edgestack, sizeof(struct improvetet));
    
    *minedge = HUGEFLOAT;
    *maxedge = 0.0;
    *meanedge = 0.0;
    
    /* initialize the iterator over the mesh */
    tetcomplexiteratorinit(mesh, &pos);
    /* retrieve the first tet in the mesh */
    tetcomplexiteratenoghosts(&pos, tet);
    
    /* for each tet */
    while (tet[0] != STOP) 
    {
        /* Look at all six edges of the tetrahedron. */
        /* Iteration over unique edges taken from Jonathan's outputedges() */
        for (i = 0; i < 6; i++) 
        {
            if (tet[0] < tet[1]) 
            {
                origin = tet[0];
                destin = tet[1];
                apex = tet[2];
                stopvtx = tet[3];
            } 
            else
            {
                origin = tet[1];
                destin = tet[0];
                apex = tet[3];
                stopvtx = tet[2];
            }
            
            searchvtx = apex;
            writeflag = 1;
            do 
            {
                if (!tetcomplexadjacencies(mesh, origin, destin, searchvtx,
                                         adjacencies)) 
                {
                    printf("Error computing edge statistics:\n");
                    printf("  Complex returned tetrahedron that can't be queried.\n");
                    internalerror();
                }
                if (adjacencies[0] == GHOSTVERTEX) 
                {
                    writeflag = searchvtx == apex;
                }
                searchvtx = adjacencies[0];
                if (searchvtx < apex) 
                {
                    writeflag = 0;
                }
            } 
            while (writeflag && (searchvtx != stopvtx) && (searchvtx != GHOSTVERTEX));
            
            /* if this is an edge that hasn't been counted yet */
            if (writeflag) 
            {
                /* measure the length of this edge */
                vcopy(((struct vertex *) tetcomplextag2vertex(mesh, origin))->coord, origcoord);
                vcopy(((struct vertex *) tetcomplextag2vertex(mesh, destin))->coord, destcoord);
                
                /* if anisotropic meshing is enabled, warp the points according the
                   deformation tensor at their barycenter */
                if (improvebehave.anisotropic && anisotropic)
                {
                    /* fetch the deformation tensor at the midpoint of this tet */
                    edgetensor(mesh, origin, destin, E);
                    
                    /* transform each vertex */
                    tensortransform(origcoord, origcoord, E);
                    tensortransform(destcoord, destcoord, E);
                }
                
                vsub(destcoord, origcoord, edge);
                edgelength = vlength(edge);
                
                /* push this edge length on the stack */
                edgetet = (struct improvetet *) stackpush(&edgestack);
                edgetet->quality = edgelength;
                
                /* keep track of minimum, maximum and average edge lengths */
                if (edgelength < *minedge) *minedge = edgelength;
                if (edgelength > *maxedge) *maxedge = edgelength;
                (*meanedge) += edgelength;
                /*
                printf("origcoord is [%g %g %g]\n", origcoord[0], origcoord[1], origcoord[2]);
                printf("destcoord is [%g %g %g]\n", destcoord[0], destcoord[1], destcoord[2]);
                printf("edglength is %g\n", edgelength);
                printf("meanedge for edgenum %d is %g\n", numedges, *meanedge);
                */
                numedges++;
            }
            
            /* The following shift cycles (tet[0], tet[1]) through all the edges   */
            /*   while maintaining the tetrahedron's orientation.  The schedule is */
            /*   i = 0:  0 1 2 3 => 1 2 0 3                                        */
            /*   i = 1:  1 2 0 3 => 1 3 2 0                                        */
            /*   i = 2:  1 3 2 0 => 3 2 1 0                                        */
            /*   i = 3:  3 2 1 0 => 3 0 2 1                                        */
            /*   i = 4:  3 0 2 1 => 0 2 3 1                                        */
            /*   i = 5:  0 2 3 1 => 0 1 2 3 (which isn't used).                    */
            if ((i & 1) == 0) 
            {
                swaptag = tet[0];
                tet[0] = tet[1];
                tet[1] = tet[2];
                tet[2] = swaptag;
            } 
            else
            {
                swaptag = tet[3];
                tet[3] = tet[2];
                tet[2] = tet[1];
                tet[1] = swaptag;
            }
        }
        
        /* fetch the next tet from the mesh */
        tetcomplexiteratenoghosts(&pos, tet);
    }
    assert(numedges != 0);
    assert(*meanedge > 0.0);
    assert(*minedge > 0.0);
    assert(*maxedge < HUGEFLOAT);
    
    /* compute average */
    *meanedge /= numedges;
    
    /* compute median */
    sortstack(&edgestack);
    *medianedge = ((struct improvetet *) arraypoolfastlookup(&(edgestack.pool), (unsigned long) (edgestack.top + 1) / 2))->quality;
    
    stackdeinit(&edgestack);
}

#define MINSIZEQUAL 1.0e-5

/* attempt to collapse edges that are too short */
void sizecontract(struct tetcomplex *mesh,
                  struct arraypoolstack *tetstack)
{
    struct arraypoolstack outstack;
    struct improvetet *stacktet, *outtet;
    bool contracted = false;
    starreal minqualbefore, minqualafter;
    
    /* for ring tet query */
    int numringtets;
    tag ringtets[MAXRINGTETS][4];
    tag bfverts[2];
    bool boundedge;
    int i;
    
    /* initialize output stack */
    stackinit(&outstack, sizeof(struct improvetet));
    
    /* go through each tet on the stack */
    while (tetstack->top != STACKEMPTY)
    {
        /* pull the top tet off the stack */
        stacktet = (struct improvetet *) stackpop(tetstack);
        
        /* check that this tet still exists */
        if (!tetexistsa(mesh, stacktet->verts))
        {
            continue;
        }
        
        /* try to contract this edge */
        contracted = edgecontract(mesh,
                                  stacktet->verts[0],
                                  stacktet->verts[1],
                                  stacktet->verts[2],
                                  stacktet->verts[3],
                                  &minqualbefore,
                                  &minqualafter,
                                  NULL, NULL,
                                  false);
        
        if (contracted)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("Succeeded in contracting edge for size control. Qual went from %g to %g\n", minqualbefore, minqualafter);
            }
        }
        else
        {
            /* we couldn't directly contract this edge. but if we can contract any edge
               of a tetrahedron that surrounds this edge, this edge will go away too */
            /* fetch all the tets that surround this edge */
            boundedge = getedgering(mesh,
                                    stacktet->verts[0],
                                    stacktet->verts[1],
                                    stacktet->verts[2],
                                    stacktet->verts[3],
                                    &numringtets, ringtets, bfverts);
            
            if (improvebehave.verbosity > 5)
            {
                printf("Couldn't directly contract short edge (%d %d). Attempting collapse on surrounding tets\n", (int) stacktet->verts[0], (int) stacktet->verts[1]);
                printf("    Edge was boundary edge: %d\n", boundedge);
                printf("    Number surrounding tets: %d\n", numringtets);
            }
            
            /* try to collapse just first edge of each tet */
            for (i=0; i<numringtets; i++)
            {
                contracted = tryedgecontract(mesh,
                                             ringtets[i][0],
                                             ringtets[i][1],
                                             ringtets[i][2],
                                             ringtets[i][3],
                                             NULL,
                                             &minqualafter,
                                             false,
                                             true);
                                             
                /* if we succeed in contracting an edge, stop trying */
                if (contracted)
                {
                    if (improvebehave.verbosity > 5)
                    {
                        printf("Contraction succeeded on subsidiary tet %d!\n", i);
                    }
                    
                    break;
                }
            }
        }
        
        if (!contracted)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("Couldn't contract any edge in size control. Adding to output stack.\n");
            }
            /* is this tet already on the output stack? */
            if (!tetinstack(&outstack, stacktet->verts[0], stacktet->verts[1], stacktet->verts[2], stacktet->verts[3]))
            {
                /* push tet on output stack */
                outtet = (struct improvetet *) stackpush(&outstack);
                outtet->verts[0] = stacktet->verts[0];
                outtet->verts[1] = stacktet->verts[1];
                outtet->verts[2] = stacktet->verts[2];
                outtet->verts[3] = stacktet->verts[3];
                outtet->quality = stacktet->quality;
            }
        }
    }
    
    /* copy the output stack over the input stack */
    copystack(&outstack, tetstack);
    /* free the local output stack */
    stackdeinit(&outstack);
}

#define SIZESPLITPARANOID 0
/* attempt to split edges that are too long */
void sizesplit(struct tetcomplex *mesh,
               struct arraypoolstack *tetstack)
{
    struct arraypoolstack outstack;
    struct improvetet *stacktet, *outtet;
    int numedgetets;
    tag edgetets[MAXRINGTETS][4];
    tag edgefaces[2];
    bool boundedge, success;
    tag vnew; 
    static tag newfaces[MAXCAVITYFACES][3]; /* faces of tets created after insert for seeding cavity drilling */
    int numnewfaces;               
    static tag newtets[MAXCAVITYTETS][4]; /* tets that filled in cavity */
    int numnewtets;
    int beforeid;
    starreal minquality = HUGEFLOAT;
    starreal worstdeletedqual, origcavityqual, cavityqual;
    starreal longest = 0.0, shortest = HUGEFLOAT;
    starreal means[NUMMEANTHRESHOLDS], meshworst, physworst;
    
    /* initialize output stack */
    stackinit(&outstack, sizeof(struct improvetet));
    
    /* go through each tet on the stack */
    while (tetstack->top != STACKEMPTY)
    {
        /* pull the top tet off the stack */
        stacktet = (struct improvetet *) stackpop(tetstack);
        
        /* check that this tet still exists */
        if (!tetexistsa(mesh, stacktet->verts))
        {
            continue;
        }
        
        /* save the mesh state before we attempt insertion */
        beforeid = lastjournalentry(); 
        
        /* fetch the ring of tets around this edge */
        boundedge = getedgering(mesh, 
                                stacktet->verts[0],
                                stacktet->verts[1],
                                stacktet->verts[2],
                                stacktet->verts[3],
                                &numedgetets,
                                edgetets, 
                                edgefaces);
        
        /* in the case of anisotropy, don't insert on boundary edge */
        /* TODO hack this out? */
        if (improvebehave.anisotropic && improvebehave.usequadrics && boundedge)
        {
            printf("bailing on sizing insertion because it's on the boundary...\n");
            continue;
        }
        
        /* attempt to insert a vertex at the midpoint of this edge */
        success = segmentinsert(mesh,
                                stacktet->verts[0],
                                stacktet->verts[1],
                                stacktet->verts[2],
                                stacktet->verts[3], 
                                numedgetets, 
                                edgetets,
                                edgefaces,
                                &vnew, 
                                newfaces, &numnewfaces,
                                newtets, &numnewtets, boundedge);
                                
        /* if that didn't work out, reverse things */
        if (!success)
        {
            if (improvebehave.verbosity > 0)
            {
                printf("Initial edge insert for size control failed\n");
            }
            invertjournalupto(mesh, beforeid);
            /* push tet on output stack */
            if (!tetinstack(&outstack, stacktet->verts[0], stacktet->verts[1], stacktet->verts[2], stacktet->verts[3]))
            {
                /* push tet on output stack */
                outtet = (struct improvetet *) stackpush(&outstack);
                outtet->verts[0] = stacktet->verts[0];
                outtet->verts[1] = stacktet->verts[1];
                outtet->verts[2] = stacktet->verts[2];
                outtet->verts[3] = stacktet->verts[3];
                outtet->quality = stacktet->quality;
            }
            continue;
        }
        
        /* insertion succeeded. dig out surrounding cavity, but don't allow vertex deletion */
        optimalcavity(mesh, vnew,
                      newtets, numnewtets, 
                      newfaces, numnewfaces, 
                      newtets, &numnewtets,
                      &worstdeletedqual,
                      &origcavityqual, false);
        
        assert(origcavityqual > 0.0);
        assert(worstdeletedqual > 0.0);
        
        /* improve the quality of tetrahedra in the cavity */
        cavityqual = improvecavity(mesh, vnew, newtets, numnewtets, false, NULL, &shortest, &longest);
        
        if (cavityqual < 0.0)
        {
            printf("improvecavity returned with negative quality %g\n", cavityqual);
        }
        
        /* ensure some minimum quality for the cavity */
        if (cavityqual < MINSIZEQUAL || shortest < (improvebehave.targetedgelength * improvebehave.shorterfactor))
        {
            if (improvebehave.verbosity > 5)
            {
                printf("Edge insertion for size control failed. Cavity qual %g, needed %g, shortest edge %g\n", cavityqual, MINSIZEQUAL, shortest);
            }
            invertjournalupto(mesh, beforeid);
            outtet = (struct improvetet *) stackpush(&outstack);
            outtet->verts[0] = stacktet->verts[0];
            outtet->verts[1] = stacktet->verts[1];
            outtet->verts[2] = stacktet->verts[2];
            outtet->verts[3] = stacktet->verts[3];
            outtet->quality = stacktet->quality;
            continue;
        }
        
        /* we successfully split the edge! */
        if (improvebehave.verbosity > 5)
        {
            printf("Succeeded in splitting too-long edge. min qual is %g\n", minquality);
        }
        
        if (SIZESPLITPARANOID)
        {
            /* compute global worst quality in isotropic space */
            meshquality(mesh, improvebehave.qualmeasure, means, &meshworst);
            if (improvebehave.anisotropic)
            {
                improvebehave.anisotropic = false;
                meshquality(mesh, improvebehave.qualmeasure, means, &physworst);
                improvebehave.anisotropic = true;
            }
            printf("after successful sizing insertion\n");
            printf("    Worst quality, isotropic = %g\n", meshworst);
            printf("    Worst quality, physical = %g\n", physworst);
            assert(meshworst > 0.0);
            assert(physworst > 0.0);
        }
    }
    
    /* copy the output stack over the input stack */
    copystack(&outstack, tetstack);
    /* free the local output stack */
    stackdeinit(&outstack);
}

/* split and collapse edges until all tetrahedra are roughly the same size */
int sizecontrol(struct tetcomplex *mesh,
                 struct behavior *behave,
                 struct inputs *in,
                 struct proxipool *vertexpool,
                 int argc,
                 char **argv)
{
    starreal minvol = HUGEFLOAT;
    starreal maxvol = 0.0;
    starreal meanvol = 0.0;
    starreal minedge = HUGEFLOAT;
    starreal maxedge = 0.0;
    starreal meanedge = 0.0;
    starreal medianedge = 0.0;
    starreal oldminedge, oldmaxedge;
    starreal shortestgoal, longestgoal;
    int numiters = 0;
    struct arraypoolstack longstack;    /* stack of tets with edges too long */
    struct arraypoolstack shortstack;   /* stack of tets with edges too short */
    struct arraypoolstack meshstack;    /* stack of all mesh tets */
    int totaltets = 0;
    starreal percentbad;
    starreal worstqual;
    starreal physworst;
    starreal means[NUMMEANTHRESHOLDS];
    
    starreal minqualbefore, minqualafter;
    starreal meanqualbefore[NUMMEANTHRESHOLDS], meanqualafter[NUMMEANTHRESHOLDS];
    starreal bestmeans[NUMMEANTHRESHOLDS];
    int smoothkinds = 0;
    
    int passstartid;
        
    if (improvebehave.facetsmooth) smoothkinds |= SMOOTHFACETVERTICES;
    if (improvebehave.segmentsmooth) smoothkinds |= SMOOTHSEGMENTVERTICES;
    if (improvebehave.fixedsmooth) smoothkinds |= SMOOTHFIXEDVERTICES;
    
    stackinit(&longstack, sizeof(struct improvetet));
    stackinit(&shortstack, sizeof(struct improvetet));
    stackinit(&meshstack, sizeof(struct improvetet));
    
    if (improvebehave.verbosity > 0)
    {
        printf("Starting size control...\n");
    }
    
    /* compute the min, max, average volume of tetrahedra in this mesh */
    volumestats(mesh, &minvol, &maxvol, &meanvol);
    
    if (improvebehave.verbosity > 1)
    {
        printf("Volume statistics:\n");
        printf("    Maximum: %g\n", maxvol);
        printf("    Minimum: %g\n", minvol);
        printf("    Average: %g\n", meanvol);
    }
    
    /* if the ideal edge length is set to zero, assign to it the value of the mean edge length */
    if (improvebehave.targetedgelength == 0.0)
    {
        /* compute physical edge length */
        edgelengthstats(mesh, &minedge, &maxedge, &meanedge, &medianedge, false);
        
        if (improvebehave.verbosity > 1)
        {
            printf("Setting ideal edge to physical median of %g\n", medianedge);
            printf("PHYSICAL SPACE Edge length statistics:\n");
            printf("    Max edge length: %g\n", maxedge);
            printf("    Min edge length: %g\n", minedge);
            printf("    Mean edge length: %g\n", meanedge);
            printf("    Median edge length: %g\n", medianedge);
        }
        
        improvebehave.targetedgelength = medianedge;
    }
    
    /* stop here unless explicit sizing pass is enabled */
    if (!improvebehave.sizingpass) return 3;
    
    /* compute anisotropic edge length */
    edgelengthstats(mesh, &minedge, &maxedge, &meanedge, &medianedge, true);
    
    longestgoal = improvebehave.targetedgelength * improvebehave.longerfactor;
    shortestgoal = improvebehave.targetedgelength * improvebehave.shorterfactor;
    
    if (improvebehave.verbosity > 1)
    {
        printf("Edge length statistics:\n");
        printf("    Max edge length: %g\n", maxedge);
        printf("    Min edge length: %g\n", minedge);
        printf("    Mean edge length: %g\n", meanedge);
        printf("    Median edge length: %g\n", medianedge);

        printf("Ideal edge length: %g\n", improvebehave.targetedgelength);
        printf("Longest allowable edge length: %g\n", longestgoal);
        printf("Shortest allowable edge length: %g\n", shortestgoal);
    }
    
    /* while some tetrahedra have edges that are too long or short, split or collapse them */
    while (
              ((minedge < shortestgoal) || (maxedge > longestgoal)) &&
              (numiters < MAXSIZEITERS)
          )
    /* while (false) */
    {
        passstartid = lastjournalentry(); 
        
        /* build stacks of tets with some edge too long or too short */
        filledgestacks(mesh, &longstack, &shortstack,
                       shortestgoal * CONTROLSHORTFAC,
                       longestgoal * CONTROLLONGFAC,
                       &minedge, &maxedge, &meanedge);
        
        /* if there aren't too many outside the bounds, bail */
        totaltets = counttets(mesh);
        percentbad = ((starreal) (longstack.top + shortstack.top)) / ((starreal) (totaltets));
        
        /* compute global worst quality in isotropic space */
        meshquality(mesh, improvebehave.qualmeasure, means, &worstqual);
        if (improvebehave.anisotropic)
        {
            improvebehave.anisotropic = false;
            meshquality(mesh, improvebehave.qualmeasure, means, &physworst);
            improvebehave.anisotropic = true;
        }
        
        if (improvebehave.verbosity > 2)
        {
            printf("Before iteration %d\n", numiters);
            printf("    Longest edge:          %g\n", maxedge);
            printf("    Longest desired edge:  %g\n", longestgoal);
            printf("    Shortest edge:         %g\n", minedge);
            printf("    Shortest desired edge: %g\n", shortestgoal);
            printf("    Mean edge:             %g\n", meanedge);
            printf("    Ideal edge:            %g\n", improvebehave.targetedgelength);
            printf("    %% Outside range:       %g\n", percentbad * 100.0);
            printf("    Worst qual (iso)       %g\n", worstqual);
            printf("    Worst qual (phys)      %g\n", physworst);
        }
        
        assert(worstqual > 0.0);
        assert(physworst > 0.0);
        
        /* stop if most are in range? */
        if (percentbad < 0.2)
        {
            break;
        }
        
        /* contract too-short edges */
        sizecontract(mesh, &shortstack);
        
        if (improvebehave.verbosity > 0)
        {
            printf("Short stack came back with %ld tets remaining\n", shortstack.top + 1 );
        }
        
        /* compute global worst quality in isotropic space */
        meshquality(mesh, improvebehave.qualmeasure, means, &worstqual);
        if (improvebehave.anisotropic)
        {
            improvebehave.anisotropic = false;
            meshquality(mesh, improvebehave.qualmeasure, means, &physworst);
            improvebehave.anisotropic = true;
        }
        printf("AFTER size contraction\n");
        printf("    Worst quality, isotropic = %g\n", worstqual);
        printf("    Worst quality, physical = %g\n", physworst);
        assert(worstqual > 0.0);
        assert(physworst > 0.0);
        
        /* split too-long edges */
        sizesplit(mesh, &longstack);
        
        if (improvebehave.verbosity > 0)
        {
            printf("Long stack came back with %ld tets remaining\n", longstack.top + 1 );
        }
        
        /* compute global worst quality in isotropic space */
        meshquality(mesh, improvebehave.qualmeasure, means, &worstqual);
        if (improvebehave.anisotropic)
        {
            improvebehave.anisotropic = false;
            meshquality(mesh, improvebehave.qualmeasure, means, &physworst);
            improvebehave.anisotropic = true;
        }
        printf("AFTER size insertion\n");
        printf("    Worst quality, isotropic = %g\n", worstqual);
        printf("    Worst quality, physical = %g\n", physworst);
        assert(worstqual > 0.0);
        assert(physworst > 0.0);
        
        oldminedge = minedge;
        oldmaxedge = maxedge;
        /* compute the same for edge length */
        edgelengthstats(mesh, &minedge, &maxedge, &meanedge, &medianedge, true);
        
        /* if there has been no reduction in extreme edge length, try a smooth + topo */
        if ((minedge <= oldminedge && maxedge >= oldmaxedge) || 1)
        {
            if (improvebehave.verbosity > 0)
            {
                printf("Performing global smoothing pass...\n");
            }
            
            /* create a stack with every tet */
            fillstackqual(mesh, &meshstack, improvebehave.qualmeasure, HUGEFLOAT, meanqualbefore, &minqualbefore);
        
            /* perform optimization smoothing pass */
            smoothpass(mesh, 
                       &meshstack, 
                       NULL, NULL, 
                       improvebehave.qualmeasure, 
                       HUGEFLOAT, 
                       bestmeans, 
                       meanqualafter, 
                       &minqualafter, 
                       smoothkinds, 
                       false);
                       
            /* create a stack with every tet */
            fillstackqual(mesh, &meshstack, improvebehave.qualmeasure, HUGEFLOAT, meanqualbefore, &minqualbefore);
            
            /* perform topological improvement pass */
            topopass(mesh, 
                     &meshstack, NULL, 
                     improvebehave.qualmeasure,
                     bestmeans, 
                     meanqualafter, 
                     &minqualafter, 
                     false);
        }
        
        /* output the mesh after this pass, if animating */
        if (improvebehave.animate)
        {
            outputqualmesh(behave, in, vertexpool, mesh, argc, argv, numiters+3, SIZECONTROLPASS, passstartid, QUALMINSINE);
        }
        
        numiters++;
    }
    
    if (improvebehave.verbosity > 0)
    {
        if (numiters < MAXSIZEITERS)
        {
            textcolor(BRIGHT, GREEN, BLACK);
            printf("Size control succeeded!\n");
            textcolor(RESET, WHITE, BLACK);
        }
        else
        {
            textcolor(BRIGHT, RED, BLACK);
            printf("Short control failed, %ld tets with too-long, %ld tets with too-short edges.\n", longstack.top+1, shortstack.top+1);
            textcolor(RESET, WHITE, BLACK);
        }
    }
    
    /* compute the same for edge length */
    edgelengthstats(mesh, &minedge, &maxedge, &meanedge, &medianedge, true);
    
    if (improvebehave.verbosity > 0)
    {
        printf("Edge length statistics after size control:\n");
        printf("    Longest edge:          %g\n", maxedge);
        printf("    Longest desired edge:  %g\n", longestgoal);
        printf("    Shortest edge:         %g\n", minedge);
        printf("    Shortest desired edge: %g\n", shortestgoal);
        printf("    Mean edge:             %g\n", meanedge);
        printf("    Median edge:           %g\n", medianedge);
        printf("    Ideal edge:            %g\n", improvebehave.targetedgelength);
    }
    
    /* outputqualmesh(behave, in, vertexpool, mesh, argc, argv, 0, SIZECONTROLPASS, 0, QUALMINSINE); */
    
    /* clean up local stacks */
    stackdeinit(&longstack);
    stackdeinit(&shortstack);
    stackdeinit(&meshstack);
    
    /* starexit(1); */
    
    return numiters+3;
}

void sizereportstream(FILE *o, struct tetcomplex *mesh)
{
    starreal minedge, maxedge, meanedge, medianedge;
    
    edgelengthstats(mesh, &minedge, &maxedge, &meanedge, &medianedge, true);
    
    fprintf(o, "Edge length statistics:\n");
    fprintf(o, "    Longest edge:          %g\n", maxedge);
    fprintf(o, "    Longest desired edge:  %g\n", improvebehave.targetedgelength * improvebehave.longerfactor);
    fprintf(o, "    Shortest edge:         %g\n", minedge);
    fprintf(o, "    Shortest desired edge: %g\n", improvebehave.targetedgelength * improvebehave.shorterfactor);
    fprintf(o, "    Mean edge:             %g\n", meanedge);
    fprintf(o, "    Median edge:           %g\n", medianedge);
    fprintf(o, "    Ideal edge:            %g\n", improvebehave.targetedgelength);
}

/* print a report on edge lengths in the mesh */
void sizereport(struct tetcomplex *mesh)
{
    sizereportstream(stdout, mesh);
}



<|start_filename|>vtkVmtk/Misc/vtkvmtkLevelSetSigmoidFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkLevelSetSigmoidFilter.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:47:48 $
Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkLevelSetSigmoidFilter - Apply a sigmoid function to every voxel of an image.
// .SECTION Description
// This is primarily used in feature image correction (see http://www.vmtk.org/tutorials/ImageFeatureCorrection.html for details). 


#ifndef __vtkvmtkLevelSetSigmoidFilter_h
#define __vtkvmtkLevelSetSigmoidFilter_h

#include "vtkSimpleImageToImageFilter.h"
#include "vtkImageData.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_MISC_EXPORT vtkvmtkLevelSetSigmoidFilter : public vtkSimpleImageToImageFilter
{
  public: 
  vtkTypeMacro(vtkvmtkLevelSetSigmoidFilter,vtkSimpleImageToImageFilter);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkLevelSetSigmoidFilter *New();

  vtkSetObjectMacro(LevelSetsImage,vtkImageData);
  vtkGetObjectMacro(LevelSetsImage,vtkImageData);

  // Get/Set  sigma value of the sigmoid function. Sigma determines the width of the sigmoid function. The value is given in pixel units.
  vtkSetMacro(Sigma,double);
  vtkGetMacro(Sigma,double);

  // Description:
  // Set/Get the Scalevalue of the sigmoind function. This determines the height of the sigmoid.
  vtkSetMacro(ScaleValue,double);
  vtkGetMacro(ScaleValue,double);

  // Description:
  // Set/Get The the ComputeScaleValueFromInput option. When enabled, vmtkimagefeaturecorrection computes the mean value from the featureimage and uses this value to set the height of the sigmoid function instead of the value given to the option scalevalue.
  vtkSetMacro(ComputeScaleValueFromInput,int);
  vtkGetMacro(ComputeScaleValueFromInput,int);
  vtkBooleanMacro(ComputeScaleValueFromInput,int);

  protected:
  vtkvmtkLevelSetSigmoidFilter();
  ~vtkvmtkLevelSetSigmoidFilter();  

  virtual void SimpleExecute(vtkImageData* input, vtkImageData* output) VTK_OVERRIDE;

  vtkImageData *LevelSetsImage;

  double Sigma;
  double ScaleValue;
  int ComputeScaleValueFromInput;

  private:
  vtkvmtkLevelSetSigmoidFilter(const vtkvmtkLevelSetSigmoidFilter&);  // Not implemented.
  void operator=(const vtkvmtkLevelSetSigmoidFilter&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Segmentation/vtkvmtkGrayscaleMorphologyImageFilter.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkGrayscaleMorphologyImageFilter.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkGrayscaleMorphologyImageFilter.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkITKFilterUtilities.h"

#include "itkBinaryBallStructuringElement.h"
#include "itkGrayscaleMorphologicalClosingImageFilter.h"
#include "itkGrayscaleMorphologicalOpeningImageFilter.h"
#include "itkGrayscaleDilateImageFilter.h"
#include "itkGrayscaleErodeImageFilter.h"


vtkStandardNewMacro(vtkvmtkGrayscaleMorphologyImageFilter);

vtkvmtkGrayscaleMorphologyImageFilter::vtkvmtkGrayscaleMorphologyImageFilter()
{
  this->BallRadius[0] = this->BallRadius[1] = this->BallRadius[2] = 1;
  this->Operation = ERODE;
}

vtkvmtkGrayscaleMorphologyImageFilter::~vtkvmtkGrayscaleMorphologyImageFilter()
{
}

int vtkvmtkGrayscaleMorphologyImageFilter::RequestInformation (
  vtkInformation * vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *outInfo = outputVector->GetInformationObject(0);
  vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_FLOAT, -1);

  return 1;
}

void vtkvmtkGrayscaleMorphologyImageFilter::SimpleExecute(vtkImageData *input, vtkImageData *output)
{
  typedef float PixelType;
  const int Dimension = 3;
  typedef itk::Image<PixelType, Dimension> ImageType;

  ImageType::Pointer inImage = ImageType::New();

  vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(input,inImage);

  typedef itk::BinaryBallStructuringElement<PixelType, Dimension> KernelType;
  typedef itk::GrayscaleMorphologicalClosingImageFilter<ImageType, ImageType, KernelType> ClosingFilterType;
  typedef itk::GrayscaleMorphologicalOpeningImageFilter<ImageType, ImageType, KernelType> OpeningFilterType;
  typedef itk::GrayscaleErodeImageFilter<ImageType, ImageType, KernelType> ErodeFilterType;
  typedef itk::GrayscaleDilateImageFilter<ImageType, ImageType, KernelType> DilateFilterType;

  KernelType ball;
  KernelType::SizeType ballRadius;
  ballRadius[0] = this->BallRadius[0];
  ballRadius[1] = this->BallRadius[1];
  ballRadius[2] = this->BallRadius[2];
  ball.SetRadius(ballRadius);
  ball.CreateStructuringElement();

  ImageType::Pointer outputImage;

  if (this->Operation == CLOSE)
    {
    ClosingFilterType::Pointer imageFilter = ClosingFilterType::New();
    imageFilter->SetKernel(ball);
    imageFilter->SetInput(inImage);
    imageFilter->SafeBorderOff();
    try {
      imageFilter->Update();
    }
    catch( itk::ExceptionObject & excep )
    {
      std::cerr << "Exception catched !" << std::endl;
      std::cerr << excep << std::endl;
    }
    outputImage = imageFilter->GetOutput();
    }
  if (this->Operation == OPEN)
    {
    OpeningFilterType::Pointer imageFilter = OpeningFilterType::New();
    imageFilter->SetKernel(ball);
    imageFilter->SetInput(inImage);
    imageFilter->SafeBorderOff();
    try {
      imageFilter->Update();
    }
    catch( itk::ExceptionObject & excep )
    {
      std::cerr << "Exception catched !" << std::endl;
      std::cerr << excep << std::endl;
    }
    outputImage = imageFilter->GetOutput();
    }
  if (this->Operation == DILATE)
    {
    DilateFilterType::Pointer imageFilter = DilateFilterType::New();
    imageFilter->SetKernel(ball);
    imageFilter->SetInput(inImage);
    try {
      imageFilter->Update();
    }
    catch( itk::ExceptionObject & excep )
    {
      std::cerr << "Exception catched !" << std::endl;
      std::cerr << excep << std::endl;
    }
    outputImage = imageFilter->GetOutput();
    }
  if (this->Operation == ERODE)
    {
    ErodeFilterType::Pointer imageFilter = ErodeFilterType::New();
    imageFilter->SetKernel(ball);
    imageFilter->SetInput(inImage);
    try {
      imageFilter->Update();
    }
    catch( itk::ExceptionObject & excep )
    {
      std::cerr << "Exception catched !" << std::endl;
      std::cerr << excep << std::endl;
    }
    outputImage = imageFilter->GetOutput();
    }

  vtkvmtkITKFilterUtilities::ITKToVTKImage<ImageType>(outputImage,output);
}



<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkEmptyNeighborhood.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkEmptyNeighborhood.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:43 $
  Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkEmptyNeighborhood - Create an an empty neighborhood instance.
// .SECTION Description
// ..

#ifndef __vtkvmtkEmptyNeighborhood_h
#define __vtkvmtkEmptyNeighborhood_h

#include "vtkObject.h"
#include "vtkvmtkConstants.h"
#include "vtkvmtkNeighborhood.h"
//#include "vtkvmtkDifferentialGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkEmptyNeighborhood : public vtkvmtkNeighborhood 
{
public:
  static vtkvmtkEmptyNeighborhood* New();
  vtkTypeMacro(vtkvmtkEmptyNeighborhood,vtkvmtkNeighborhood);

  virtual vtkIdType GetItemType() VTK_OVERRIDE {return VTK_VMTK_EMPTY_NEIGHBORHOOD;};

  // Description:
  // Build the stencil.
  void Build() VTK_OVERRIDE;

protected:
  vtkvmtkEmptyNeighborhood() {};
  ~vtkvmtkEmptyNeighborhood() {};

private:
  vtkvmtkEmptyNeighborhood(const vtkvmtkEmptyNeighborhood&);  // Not implemented.
  void operator=(const vtkvmtkEmptyNeighborhood&);  // Not implemented.
};

#endif



<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataFlowExtensionsFilter.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkPolyDataFlowExtensionsFilter.cxx,v $
Language:  C++
Date:      $Date: 2006/07/07 10:46:19 $
Version:   $Revision: 1.12 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataFlowExtensionsFilter.h"
#include "vtkvmtkPolyDataBoundaryExtractor.h"
#include "vtkvmtkBoundaryReferenceSystems.h"
#include "vtkvmtkPolyBallLine.h"
#include "vtkvmtkMath.h"
#include "vtkThinPlateSplineTransform.h"
#include "vtkTransform.h"
#include "vtkPolyLine.h"
#include "vtkPointData.h"
#include "vtkDoubleArray.h"
#include "vtkIntArray.h"
#include "vtkMath.h"
#include "vtkCellArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkVersion.h"


vtkStandardNewMacro(vtkvmtkPolyDataFlowExtensionsFilter);

vtkvmtkPolyDataFlowExtensionsFilter::vtkvmtkPolyDataFlowExtensionsFilter()
{
  this->Centerlines = NULL;
  this->ExtensionRatio = 1.0;
  this->TransitionRatio = 0.5;
  this->ExtensionLength = 0.0;
  this->ExtensionRadius = 1.0;
  this->CenterlineNormalEstimationDistanceRatio = 1.0;
  this->AdaptiveExtensionLength = 1;
  this->AdaptiveExtensionRadius = 1;
  this->NumberOfBoundaryPoints = 50;
  this->AdaptiveNumberOfBoundaryPoints = 0;
  this->BoundaryIds = NULL;
  this->Sigma = 1.0;
  this->SetExtensionModeToUseCenterlineDirection();
  this->SetInterpolationModeToThinPlateSpline();
}

vtkvmtkPolyDataFlowExtensionsFilter::~vtkvmtkPolyDataFlowExtensionsFilter()
{
  if (this->Centerlines)
    {
    this->Centerlines->Delete();
    this->Centerlines = NULL;
    }

  if (this->BoundaryIds)
    {
    this->BoundaryIds->Delete();
    this->BoundaryIds = NULL;
    }
}

int vtkvmtkPolyDataFlowExtensionsFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (this->ExtensionMode == USE_CENTERLINE_DIRECTION)
    {
    if (!this->Centerlines)
      {
      vtkErrorMacro(<< "Centerlines not set.");
      return 1;
      }
    }

  vtkPoints* outputPoints = vtkPoints::New();
  vtkCellArray* outputPolys = vtkCellArray::New();

  outputPoints->DeepCopy(input->GetPoints());
  outputPolys->DeepCopy(input->GetPolys());

  vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New();
#if (VTK_MAJOR_VERSION <= 5)
  boundaryExtractor->SetInput(input);
#else
  boundaryExtractor->SetInputData(input);
#endif

  boundaryExtractor->Update();

  vtkPolyData* boundaries = boundaryExtractor->GetOutput();

  vtkPolyData* centerlines = vtkPolyData::New();
  vtkvmtkPolyBallLine* tube = vtkvmtkPolyBallLine::New();
  vtkDoubleArray* zeroRadiusArray = vtkDoubleArray::New();

  if (this->ExtensionMode == USE_CENTERLINE_DIRECTION)
    {
    centerlines->DeepCopy(this->Centerlines);

    const char zeroRadiusArrayName[] = "ZeroRadiusArray";

    zeroRadiusArray->SetName(zeroRadiusArrayName);
    zeroRadiusArray->SetNumberOfTuples(centerlines->GetNumberOfPoints());
    zeroRadiusArray->FillComponent(0,0.0);
    
    centerlines->GetPointData()->AddArray(zeroRadiusArray);
  
    tube->SetInput(centerlines);
    tube->SetPolyBallRadiusArrayName(zeroRadiusArrayName);
    }

  input->BuildCells();
  input->BuildLinks();

  int i, k;
  for (i=0; i<boundaries->GetNumberOfCells(); i++)
    {
    if (this->BoundaryIds)
      {
      if (this->BoundaryIds->IsId(i) == -1)
        {
        continue;
        }
      }
    
    vtkPolyLine* boundary = vtkPolyLine::SafeDownCast(boundaries->GetCell(i));

    if (!boundary)
      {
      vtkErrorMacro(<<"Boundary not a vtkPolyLine");
      continue;
      }

    int numberOfBoundaryPoints = boundary->GetNumberOfPoints();

    vtkIdList* boundaryIds = vtkIdList::New();
    int j;
    for (j=0; j<numberOfBoundaryPoints; j++)
      {
      boundaryIds->InsertNextId(static_cast<vtkIdType>(vtkMath::Round(boundaries->GetPointData()->GetScalars()->GetComponent(boundary->GetPointId(j),0))));
      }
    
    double barycenter[3];
    double normal[3], outwardNormal[3];
    double meanRadius;

    vtkvmtkBoundaryReferenceSystems::ComputeBoundaryBarycenter(boundary->GetPoints(),barycenter);
    meanRadius = vtkvmtkBoundaryReferenceSystems::ComputeBoundaryMeanRadius(boundary->GetPoints(),barycenter);
    vtkvmtkBoundaryReferenceSystems::ComputeBoundaryNormal(boundary->GetPoints(),barycenter,normal);
    vtkvmtkBoundaryReferenceSystems::OrientBoundaryNormalOutwards(input,boundaries,i,normal,outwardNormal);

    double flowExtensionNormal[3];
    flowExtensionNormal[0] = flowExtensionNormal[1] = flowExtensionNormal[2] = 0.0;  
 
    if (this->ExtensionMode == USE_CENTERLINE_DIRECTION)
      {
      tube->EvaluateFunction(barycenter);
  
      double centerlinePoint[3];
      vtkIdType cellId, subId;
      double pcoord;
      tube->GetLastPolyBallCenter(centerlinePoint);
      cellId = tube->GetLastPolyBallCellId();
      subId = tube->GetLastPolyBallCellSubId();
      pcoord = tube->GetLastPolyBallCellPCoord();
  
      vtkCell* centerline = centerlines->GetCell(cellId);
  
      vtkIdType pointId0, pointId1;
      double abscissa;
  
      double point0[3], point1[3];
  
      pointId0 = 0;
      abscissa = sqrt(vtkMath::Distance2BetweenPoints(centerlinePoint,centerline->GetPoints()->GetPoint(subId)));
      for (j=subId-1; j>=0; j--)
        {
        centerline->GetPoints()->GetPoint(j,point0);
        centerline->GetPoints()->GetPoint(j+1,point1);
        abscissa += sqrt(vtkMath::Distance2BetweenPoints(point0,point1));
        if (abscissa > meanRadius * this->CenterlineNormalEstimationDistanceRatio)
          {
          pointId0 = j;
          break;
          }
        }
  
      pointId1 = centerline->GetNumberOfPoints()-1;
      abscissa = sqrt(vtkMath::Distance2BetweenPoints(centerlinePoint,centerline->GetPoints()->GetPoint(subId+1)));
      for (j=subId+1; j<centerline->GetNumberOfPoints()-2; j++)
        {
        centerline->GetPoints()->GetPoint(j,point0);
        centerline->GetPoints()->GetPoint(j+1,point1);
        abscissa += sqrt(vtkMath::Distance2BetweenPoints(point0,point1));
        if (abscissa > meanRadius * this->CenterlineNormalEstimationDistanceRatio)
          {
          pointId1 = j+1;
          break;
          }
        }
  
      // use an approximating spline or smooth centerline points to better catch the trend in computing centerlineNormal?
  
      double centerlineNormal[3];
  
      centerline->GetPoints()->GetPoint(pointId0,point0);
      centerline->GetPoints()->GetPoint(pointId1,point1);
  
      double toleranceFactor = 1E-4;
  
      for (k=0; k<3; k++)
        {
        centerlineNormal[k] = 0.0;
        }
      if (sqrt(vtkMath::Distance2BetweenPoints(point1,centerlinePoint)) > toleranceFactor*meanRadius)
        {
        for (k=0; k<3; k++)
          {
          centerlineNormal[k] += point1[k] - centerlinePoint[k];
          }
        } 
      if (sqrt(vtkMath::Distance2BetweenPoints(centerlinePoint,point0)) > toleranceFactor*meanRadius)
        {
        for (k=0; k<3; k++)
          {
          centerlineNormal[k] += centerlinePoint[k] - point0[k];
          }
        }
  
      vtkMath::Normalize(centerlineNormal);
  
      for (k=0; k<3; k++)
        {
        flowExtensionNormal[k] = centerlineNormal[k];
        }
  
      if (vtkMath::Dot(outwardNormal,centerlineNormal) < 0.0)
        {
        for (k=0; k<3; k++)
          {
          flowExtensionNormal[k] *= -1.0;
          }
        }
      }
    else if (this->ExtensionMode == USE_NORMAL_TO_BOUNDARY)
      {
      for (k=0; k<3; k++)
        {
        flowExtensionNormal[k] = outwardNormal[k];
        }
      }
    else
      {
      vtkErrorMacro(<< "Invalid ExtensionMode.");
      return 1;
      }

    double extensionLength;

    if (this->AdaptiveExtensionLength)
      {
      extensionLength = meanRadius * this->ExtensionRatio;
      }
    else
      {
      extensionLength = this->ExtensionLength;
      }

    double point[3], extensionPoint[3];
    double targetRadius = 0.0;

    if (this->AdaptiveExtensionRadius)
      {
      double barycenterToPoint[3];
      double outOfPlaneDistance;
      double projectedBarycenterToPoint[3];
      for (j=0; j<numberOfBoundaryPoints; j++)
        {
        boundary->GetPoints()->GetPoint(j,point);
        for (k=0; k<3; k++)
          {
          barycenterToPoint[k] = point[k] - barycenter[k];
          }
        outOfPlaneDistance = vtkMath::Dot(barycenterToPoint,flowExtensionNormal);
        for (k=0; k<3; k++)
          {
          projectedBarycenterToPoint[k] = barycenterToPoint[k] - outOfPlaneDistance*flowExtensionNormal[k];
          }
        targetRadius += vtkMath::Norm(projectedBarycenterToPoint);
        }
      targetRadius /= numberOfBoundaryPoints;
      }
    else
      {
      targetRadius = this->ExtensionRadius;
      }

    vtkIdList* newBoundaryIds = vtkIdList::New();
    vtkIdList* previousBoundaryIds = vtkIdList::New();
    vtkIdType pointId;

    previousBoundaryIds->DeepCopy(boundaryIds);

    // TODO: use area, not meanRadius as targetRadius

    int targetNumberOfBoundaryPoints = this->NumberOfBoundaryPoints;
    if (this->AdaptiveNumberOfBoundaryPoints)
      {
      targetNumberOfBoundaryPoints = numberOfBoundaryPoints;
      }

    double targetDistanceBetweenPoints = 2.0 * sin (vtkMath::Pi() / targetNumberOfBoundaryPoints) * targetRadius;

    vtkThinPlateSplineTransform* thinPlateSplineTransform = vtkThinPlateSplineTransform::New();
    thinPlateSplineTransform->SetSigma(this->Sigma);
    thinPlateSplineTransform->SetBasisToR2LogR();
//    thinPlateSplineTransform->SetBasisToR();
    
    vtkPoints* sourceLandmarks = vtkPoints::New();
    vtkPoints* targetLandmarks = vtkPoints::New();

    vtkPoints* targetBoundaryPoints = vtkPoints::New();
    vtkPoints* targetStaggeredBoundaryPoints = vtkPoints::New();

    double baseRadialNormal[3];
    input->GetPoint(previousBoundaryIds->GetId(0),point);
    for (k=0; k<3; k++)
      {
      baseRadialNormal[k] = point[k] - barycenter[k];
      }
    double outOfPlaneComponent = vtkMath::Dot(baseRadialNormal,flowExtensionNormal);
    for (k=0; k<3; k++)
      {
      baseRadialNormal[k] -= outOfPlaneComponent * flowExtensionNormal[k];
      }
    vtkMath::Normalize(baseRadialNormal);
    int startNumberOfBoundaryPoints = numberOfBoundaryPoints;
    double angle = 360.0 / targetNumberOfBoundaryPoints;
    vtkTransform* transform = vtkTransform::New();
    transform->RotateWXYZ(0.5*angle,flowExtensionNormal);
    double testRadialNormal[3];
    transform->TransformPoint(baseRadialNormal,testRadialNormal);
    double cross[3], testCross[3], point1[3];
    vtkMath::Cross(baseRadialNormal,testRadialNormal,testCross);
    double dist = 0.0;
    int testId = 1;
    int numberOfPreviousBoundaryIds = previousBoundaryIds->GetNumberOfIds();
    while (dist < 1E-8 && testId < numberOfPreviousBoundaryIds)
      {
      input->GetPoint(previousBoundaryIds->GetId(testId),point1);
      dist = sqrt(vtkMath::Distance2BetweenPoints(point,point1));
      testId++;
      }
    double testRadialVector[3];
    for (k=0; k<3; k++)
      {
      testRadialVector[k] = point1[k] - barycenter[k];
      }
    vtkMath::Cross(baseRadialNormal,testRadialVector,cross);
    if (vtkMath::Dot(cross,testCross) < 0.0)
      {
      angle *= -1.0;
      transform->Identity();
      transform->RotateWXYZ(0.5*angle,flowExtensionNormal); 
      }
    double radialVector[3];
    for (k=0; k<3; k++)
      {
      radialVector[k] = targetRadius * baseRadialNormal[k];
      }
    double targetPoint[3];
    for (j=0; j<targetNumberOfBoundaryPoints; j++)
      {
      for (k=0; k<3; k++)
        {
        targetPoint[k] = barycenter[k] + radialVector[k];
        }
      targetBoundaryPoints->InsertNextPoint(targetPoint);
      transform->TransformPoint(radialVector,radialVector);
      for (k=0; k<3; k++)
        {
        targetPoint[k] = barycenter[k] + radialVector[k];
        }
      targetStaggeredBoundaryPoints->InsertNextPoint(targetPoint);
      transform->TransformPoint(radialVector,radialVector);
      }
    transform->Delete();
    
    if (this->InterpolationMode == USE_THIN_PLATE_SPLINE_INTERPOLATION)
      {
      for (j=0; j<targetNumberOfBoundaryPoints; j++)
        {
        double firstBoundaryPoint[3], lastBoundaryPoint[3];
        targetBoundaryPoints->GetPoint(j,firstBoundaryPoint);
        double distance = 1E20;
        double currentPoint[3];
        for (int j2=0; j2<startNumberOfBoundaryPoints; j2++)
          {
          input->GetPoint(previousBoundaryIds->GetId(j2),currentPoint);
          double currentDistance = vtkMath::Distance2BetweenPoints(currentPoint,firstBoundaryPoint);
          if (currentDistance < distance)
            {
            distance = currentDistance;
            for (k=0; k<3; k++)
              {
              point[k] = currentPoint[k];
              }
            }
          }
        sourceLandmarks->InsertNextPoint(firstBoundaryPoint);
        targetLandmarks->InsertNextPoint(point);
        for (k=0; k<3; k++)
          { 
          lastBoundaryPoint[k] = firstBoundaryPoint[k] + extensionLength * this->TransitionRatio * flowExtensionNormal[k]; 
          }
        sourceLandmarks->InsertNextPoint(lastBoundaryPoint);
        targetLandmarks->InsertNextPoint(lastBoundaryPoint);
        }
      thinPlateSplineTransform->SetSourceLandmarks(sourceLandmarks);
      thinPlateSplineTransform->SetTargetLandmarks(targetLandmarks);
      }

    int numberOfLayers = extensionLength / targetDistanceBetweenPoints;
    int numberOfTransitionLayers = (extensionLength * this->TransitionRatio) / targetDistanceBetweenPoints;
    int l;
    for (l=0; l<numberOfLayers; l++)
      {
      newBoundaryIds->Initialize();
      for (j=0; j<targetNumberOfBoundaryPoints; j++)
        {
        if (l%2 != 0)
          {
          targetBoundaryPoints->GetPoint(j,extensionPoint);
          }
        else
          {
          targetStaggeredBoundaryPoints->GetPoint(j,extensionPoint);
          }
        for (k=0; k<3; k++)
          {
          extensionPoint[k] += (l+1) * targetDistanceBetweenPoints * flowExtensionNormal[k];
          }
        if (l<numberOfTransitionLayers)
          {
          if (this->InterpolationMode == USE_LINEAR_INTERPOLATION)
            {
            }
          else if (this->InterpolationMode == USE_THIN_PLATE_SPLINE_INTERPOLATION)
            {
            thinPlateSplineTransform->TransformPoint(extensionPoint,extensionPoint);
            }
          }
        pointId = outputPoints->InsertNextPoint(extensionPoint);
        newBoundaryIds->InsertNextId(pointId);
        }

      if (l==0)
        {
        vtkIdType pts[3];
        int j2 = 0;
        for (j=0; j<targetNumberOfBoundaryPoints; j++)
          {
          double point0[3], point1[3], point2[3], point3[3];
          outputPoints->GetPoint(previousBoundaryIds->GetId(j2%startNumberOfBoundaryPoints),point0);
          outputPoints->GetPoint(previousBoundaryIds->GetId((j2+1)%startNumberOfBoundaryPoints),point1);
          outputPoints->GetPoint(newBoundaryIds->GetId(j),point2);
          outputPoints->GetPoint(newBoundaryIds->GetId((j+1)%targetNumberOfBoundaryPoints),point3);

          bool advance = false;
          if ((j==0) || (j==targetNumberOfBoundaryPoints-1) || (vtkMath::Distance2BetweenPoints(point0,point3) > vtkMath::Distance2BetweenPoints(point1,point2)))
            {
            advance = true;
            }
          if (j2 == startNumberOfBoundaryPoints)
            {
            advance = false;
            }
          while(advance) 
            {
            pts[0] = previousBoundaryIds->GetId(j2%startNumberOfBoundaryPoints);
            pts[1] = newBoundaryIds->GetId(j);
            pts[2] = previousBoundaryIds->GetId((j2+1)%startNumberOfBoundaryPoints);
            outputPolys->InsertNextCell(3,pts);
            j2 += 1;

            outputPoints->GetPoint(previousBoundaryIds->GetId(j2%startNumberOfBoundaryPoints),point0);
            outputPoints->GetPoint(previousBoundaryIds->GetId((j2+1)%startNumberOfBoundaryPoints),point1);
            outputPoints->GetPoint(newBoundaryIds->GetId(j),point2);
            outputPoints->GetPoint(newBoundaryIds->GetId((j+1)%targetNumberOfBoundaryPoints),point3);

            if (j2 == startNumberOfBoundaryPoints || vtkMath::Distance2BetweenPoints(point0,point3) < vtkMath::Distance2BetweenPoints(point1,point2))
              {
              advance = false;
              if (j2 < startNumberOfBoundaryPoints && j == targetNumberOfBoundaryPoints-1)
                {
                advance = true;
                }
              }
            }
          pts[0] = newBoundaryIds->GetId(j);
          pts[1] = newBoundaryIds->GetId((j+1)%targetNumberOfBoundaryPoints);
          pts[2] = previousBoundaryIds->GetId(j2%startNumberOfBoundaryPoints);
          outputPolys->InsertNextCell(3,pts);
          }
        }
      else
        {
        vtkIdType pts[3];
        for (j=0; j<targetNumberOfBoundaryPoints; j++)
          {
          if (l%2 != 0)
            {
            pts[0] = newBoundaryIds->GetId(j);
            pts[1] = newBoundaryIds->GetId((j-1+targetNumberOfBoundaryPoints)%targetNumberOfBoundaryPoints);
            pts[2] = previousBoundaryIds->GetId((j-1+targetNumberOfBoundaryPoints)%targetNumberOfBoundaryPoints);
            outputPolys->InsertNextCell(3,pts);
  
            pts[0] = previousBoundaryIds->GetId(j);
            pts[1] = newBoundaryIds->GetId(j);
            pts[2] = previousBoundaryIds->GetId((j-1+targetNumberOfBoundaryPoints)%targetNumberOfBoundaryPoints);
            outputPolys->InsertNextCell(3,pts);
            }
          else
            {
            pts[0] = newBoundaryIds->GetId(j);
            pts[1] = newBoundaryIds->GetId((j-1+targetNumberOfBoundaryPoints)%targetNumberOfBoundaryPoints);
            pts[2] = previousBoundaryIds->GetId(j);
            outputPolys->InsertNextCell(3,pts);
    
            pts[0] = previousBoundaryIds->GetId(j);
            pts[1] = newBoundaryIds->GetId((j-1+targetNumberOfBoundaryPoints)%targetNumberOfBoundaryPoints);
            pts[2] = previousBoundaryIds->GetId((j-1+targetNumberOfBoundaryPoints)%targetNumberOfBoundaryPoints);
            outputPolys->InsertNextCell(3,pts);
            }
          }
        }

      previousBoundaryIds->DeepCopy(newBoundaryIds);
      }

    targetBoundaryPoints->Delete();
    targetStaggeredBoundaryPoints->Delete();
    newBoundaryIds->Delete();
    previousBoundaryIds->Delete();
    boundaryIds->Delete();
    thinPlateSplineTransform->Delete();
    sourceLandmarks->Delete();
    targetLandmarks->Delete();
    }

  output->SetPoints(outputPoints);
  output->SetPolys(outputPolys);

  outputPoints->Delete();
  outputPolys->Delete();

  tube->Delete();
  zeroRadiusArray->Delete();
  boundaryExtractor->Delete();

  return 1;
}

void vtkvmtkPolyDataFlowExtensionsFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


<|start_filename|>vtkVmtk/Segmentation/vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.2 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

// .NAME vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter - Wrapper class around itk::GradientMagnitudeRecursiveGaussian2DImageFilter
// .SECTION Description
// vtkvmtkGradientMagnitudeImageFilter


#ifndef __vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter_h
#define __vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter_h

#include "vtkSimpleImageToImageFilter.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter : public vtkSimpleImageToImageFilter
{
 public:
  static vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter *New();
  vtkTypeMacro(vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter, vtkSimpleImageToImageFilter);

  vtkGetMacro(Sigma,double);
  vtkSetMacro(Sigma,double);

  vtkGetMacro(NormalizeAcrossScale,int);
  vtkSetMacro(NormalizeAcrossScale,int);
  vtkBooleanMacro(NormalizeAcrossScale,int);

protected:
  vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter();
  ~vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter() {};

  virtual void SimpleExecute(vtkImageData* input, vtkImageData* output) VTK_OVERRIDE;

private:
  vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter(const vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter&);  // Not implemented.
  void operator=(const vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter&);  // Not implemented.

  double Sigma;
  int NormalizeAcrossScale;
};

#endif



<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkItems.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkItems.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:43 $
  Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkItems - Control allocation and memory footprint of item instances. 
// .SECTION Description
// ..

#ifndef __vtkvmtkItems_h
#define __vtkvmtkItems_h

#include "vtkObject.h"
#include "vtkvmtkItem.h"
#include "vtkDataSet.h"
//#include "vtkvmtkDifferentialGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkItems : public vtkObject 
{
public:

  vtkTypeMacro(vtkvmtkItems,vtkObject);

  vtkSetMacro(ItemType,int);
  vtkGetMacro(ItemType,int);

  // Description:
  // Allocate the specified number of items (i.e., number of points) that
  // will be built.
  void Allocate(vtkIdType numItems, vtkIdType ext=1000);

  vtkvmtkItem* GetItem(vtkIdType id) {return this->Array[id];};

  void SetNumberOfItems(vtkIdType numberOfItems) { this->MaxId = numberOfItems - 1;};
  vtkIdType GetNumberOfItems() {return this->MaxId + 1;};

  // Description:
  // Reclaim any unused memory.
  void Squeeze();

  // Description:
  // Reset to a state of no entries without freeing the memory.
  void Reset();

  // Description:
  // Reset to a state of no entries freeing the memory.
  void Initialize();

  // Description:
  // Releases the stencil array.
  void ReleaseArray();

  void AllocateItem(vtkIdType i, vtkIdType itemType);

  // Description:
  // Standard DeepCopy method.
  void DeepCopy(vtkvmtkItems *src);

  // Description:
  // Standard ShallowCopy method.
  void ShallowCopy(vtkvmtkItems *src);

protected:
  vtkvmtkItems():Array(NULL),Size(0),MaxId(-1),Extend(1000) {};
  ~vtkvmtkItems();

  virtual vtkvmtkItem* InstantiateNewItem(int itemType) = 0;

  vtkvmtkItem** Array;   // pointer to data
  vtkIdType Size;       // allocated size of data
  vtkIdType MaxId;     // maximum index inserted thus far
  vtkIdType Extend;     // grow array by this point
  vtkvmtkItem** Resize(vtkIdType sz);  // function to resize data

  int ItemType;

private:
  vtkvmtkItems(const vtkvmtkItems&);  // Not implemented.
  void operator=(const vtkvmtkItems&);  // Not implemented.
};

#endif



<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineProjection.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkPolyDataCenterlineProjection.cxx,v $
  Language:  C++
  Date:      $Date: 2005/03/31 15:07:48 $
  Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataCenterlineProjection.h"
#include "vtkPointData.h"
#include "vtkvmtkPolyBallLine.h"
#include "vtkCell.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkPolyDataCenterlineProjection);

vtkvmtkPolyDataCenterlineProjection::vtkvmtkPolyDataCenterlineProjection() 
{
  this->Centerlines = NULL;
  this->CenterlineRadiusArrayName = NULL;

  this->UseRadiusInformation = 1;
}

vtkvmtkPolyDataCenterlineProjection::~vtkvmtkPolyDataCenterlineProjection()
{
  if (this->Centerlines)
    {
    this->Centerlines->Delete();
    this->Centerlines = NULL;
    }

  if (this->CenterlineRadiusArrayName)
    {
    delete[] this->CenterlineRadiusArrayName;
    this->CenterlineRadiusArrayName = NULL;
    }
}

int vtkvmtkPolyDataCenterlineProjection::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (!this->Centerlines)
    {
    vtkErrorMacro(<<"Centerlines not set");
    return 1;
    }

  if (this->UseRadiusInformation)
    {
    if (!this->CenterlineRadiusArrayName)
      {
      vtkErrorMacro(<<"CenterlineRadiusArrayName not set.");
      return 1;
      }

    vtkDataArray* centerlineRadiusArray = this->Centerlines->GetPointData()->GetArray(this->CenterlineRadiusArrayName);
    
    if (!centerlineRadiusArray)
      {
      vtkErrorMacro(<<"CenterlineRadiusArrayName with name specified does not exist.");
      return 1;
      }
    }

  int numberOfInputPoints = input->GetNumberOfPoints();

  output->DeepCopy(input);

  vtkPointData* outputPointData = output->GetPointData();
  vtkPointData* referencePointData = this->Centerlines->GetPointData();

  outputPointData->InterpolateAllocate(referencePointData,numberOfInputPoints);

  vtkvmtkPolyBallLine* tube = vtkvmtkPolyBallLine::New();
  tube->SetInput(this->Centerlines);
  tube->SetUseRadiusInformation(this->UseRadiusInformation);
  if (this->UseRadiusInformation)
    {
    tube->SetPolyBallRadiusArrayName(this->CenterlineRadiusArrayName);
    }

  double point[3];
  for (int i=0; i<numberOfInputPoints; i++)
    {
    input->GetPoint(i,point);
    tube->EvaluateFunction(point);
    vtkIdType cellId = tube->GetLastPolyBallCellId();
    vtkIdType subId = tube->GetLastPolyBallCellSubId();
    double pcoord = tube->GetLastPolyBallCellPCoord();
    vtkCell* cell = this->Centerlines->GetCell(cellId);
//  FIXME: for some reason EvaluateLocation fails on the PolyLine - weights are funny. Copy from the closest subId for the moment.
//    double pcoords[3];
//    pcoords[0] = pcoord;
//    pcoords[1] = pcoords[2] = 0.0;
//    double* weights = new double[cell->GetNumberOfPoints()];
//    double locationPoint[3];
//    cell->EvaluateLocation(subId,pcoords,locationPoint,weights);
//    outputPointData->InterpolatePoint(referencePointData,i,cell->GetPointIds(),weights); 
//    delete[] weights;
    if (pcoord < 0.5)
      {
      outputPointData->CopyData(referencePointData,cell->GetPointId(subId),i);
      }
    else
      {
      outputPointData->CopyData(referencePointData,cell->GetPointId(subId+1),i);
      }
    }

  tube->Delete();

  return 1;
}


<|start_filename|>distribution/legacy/nsis/mingw-postinst.bat<|end_filename|>
@echo off

rem Strip off leading 'lib' on .pyd files

setlocal EnableDelayedExpansion

set VMTK_DIR=%~dp0
cd "%VMTK_DIR%lib\vtk-5.6"
for %%f in (lib*.pyd) do (
  set pydfile=%%f
  move /y !pydfile! !pydfile:lib=!
)

cd "%VMTK_DIR%lib\vmtk\vmtk"
for %%f in (lib*.pyd) do (
  set pydfile=%%f
  move /y !pydfile! !pydfile:lib=!
)


<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkFEShapeFunctions.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkFEShapeFunctions.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:44 $
  Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkFEShapeFunctions - Set of common utility (calculate jacobian, interpolation function, and interpolation function derivatives) functions used during assembly of certain finite element solutions.
// .SECTION Description
// ..

#ifndef __vtkvmtkFEShapeFunctions_h
#define __vtkvmtkFEShapeFunctions_h

#include "vtkObject.h"
#include "vtkvmtkWin32Header.h"

#include "vtkCell.h"
#include "vtkDoubleArray.h"

class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkFEShapeFunctions : public vtkObject
{
public:
  vtkTypeMacro(vtkvmtkFEShapeFunctions,vtkObject);
  static vtkvmtkFEShapeFunctions* New();

  void Initialize(vtkCell* cell, vtkDoubleArray* pcoords);

  double GetPhi(vtkIdType id, vtkIdType i)
  { return this->Phi->GetValue(id*this->NumberOfCellPoints+i); }

  double* GetDPhi(vtkIdType id, vtkIdType i)
  { return this->DPhi->GetTuple(id*this->NumberOfCellPoints+i); }

  void GetDPhi(vtkIdType id, vtkIdType i, double* dphi)
  { this->DPhi->GetTuple(id*this->NumberOfCellPoints+i,dphi); }

  double GetDPhi(vtkIdType id, vtkIdType i, int c)
  { return this->DPhi->GetComponent(id*this->NumberOfCellPoints+i,c); }

  double GetJacobian(vtkIdType i)
  { return this->Jacobians->GetValue(i); }

  static void GetInterpolationFunctions(vtkCell* cell, double* pcoords, double* sf);
  static void GetInterpolationDerivs(vtkCell* cell, double* pcoords, double* derivs);
 
  static double ComputeJacobian(vtkCell* cell, double* pcoords);

protected:
  vtkvmtkFEShapeFunctions();
  ~vtkvmtkFEShapeFunctions();
 
  static void ComputeInverseJacobianMatrix2D(vtkCell* cell, double* pcoords, double inverseJacobianMatrix[2][3]);
  static void ComputeInverseJacobianMatrix3D(vtkCell* cell, double* pcoords, double inverseJacobianMatrix[3][3]);

  vtkDoubleArray* Phi;
  vtkDoubleArray* DPhi;
  vtkDoubleArray* Jacobians;
  vtkIdType NumberOfCellPoints;

private:  
  vtkvmtkFEShapeFunctions(const vtkvmtkFEShapeFunctions&);  // Not implemented.
  void operator=(const vtkvmtkFEShapeFunctions&);  // Not implemented.

};

#endif


<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkDirichletBoundaryConditions.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkDirichletBoundaryConditions.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:43 $
  Version:   $Revision: 1.3 $

  Copyright (c) <NAME> 

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkDirichletBoundaryConditions - Set up a Dirichlet (or first-type) boundary conditions that a linear system needs to take along the boundary of the domain.
// .SECTION Description
// ..

#ifndef __vtkvmtkDirichletBoundaryConditions_h
#define __vtkvmtkDirichletBoundaryConditions_h

#include "vtkObject.h"
#include "vtkvmtkBoundaryConditions.h"
//#include "vtkvmtkDifferentialGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkDirichletBoundaryConditions : public vtkvmtkBoundaryConditions
{
public:
  static vtkvmtkDirichletBoundaryConditions* New();
  vtkTypeMacro(vtkvmtkDirichletBoundaryConditions,vtkvmtkBoundaryConditions);

  void Apply() VTK_OVERRIDE;

protected:
  vtkvmtkDirichletBoundaryConditions() {};
  ~vtkvmtkDirichletBoundaryConditions() {};

private:
  vtkvmtkDirichletBoundaryConditions(const vtkvmtkDirichletBoundaryConditions&);  // Not implemented.
  void operator=(const vtkvmtkDirichletBoundaryConditions&);  // Not implemented.
};

#endif



<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataCylinderHarmonicMappingFilter.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkPolyDataCylinderHarmonicMappingFilter.cxx,v $
  Language:  C++
  Date:      $Date: 2005/03/31 15:07:53 $
  Version:   $Revision: 1.5 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataCylinderHarmonicMappingFilter.h"
#include "vtkPolyData.h"
#include "vtkPointData.h"
#include "vtkCell.h"
#include "vtkvmtkPolyDataBoundaryExtractor.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkVersion.h"


vtkStandardNewMacro(vtkvmtkPolyDataCylinderHarmonicMappingFilter);

vtkvmtkPolyDataCylinderHarmonicMappingFilter::vtkvmtkPolyDataCylinderHarmonicMappingFilter() 
{
}

vtkvmtkPolyDataCylinderHarmonicMappingFilter::~vtkvmtkPolyDataCylinderHarmonicMappingFilter()
{
}

int vtkvmtkPolyDataCylinderHarmonicMappingFilter::RequestData(
  vtkInformation *request,
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New();
#if (VTK_MAJOR_VERSION <= 5)
  boundaryExtractor->SetInput(input);
#else
  boundaryExtractor->SetInputData(input);
#endif
  boundaryExtractor->Update();

  vtkPolyData* boundaries = boundaryExtractor->GetOutput();
  
  int numberOfBoundaries = boundaries->GetNumberOfCells();

  if (numberOfBoundaries != 2)
    {
    vtkWarningMacro(<<"Input poly data is not topologically a cylinder.");
    boundaryExtractor->Delete();
    this->GetOutput()->DeepCopy(input);
    return 1;
    }

  if (this->BoundaryPointIds)
    {
    this->BoundaryPointIds->Delete();
    }

  if (this->BoundaryValues)
    {
    this->BoundaryValues->Delete();
    }

  this->BoundaryPointIds = vtkIdList::New();
  this->BoundaryValues = vtkDoubleArray::New();

  for (int i=0; i<numberOfBoundaries; i++)
    {
    vtkCell* boundaryCell = boundaries->GetCell(i);

    for (int j=0; j<boundaryCell->GetNumberOfPoints(); j++)
      {
      this->BoundaryPointIds->InsertNextId(static_cast<vtkIdType>(boundaries->GetPointData()->GetScalars()->GetTuple1(boundaryCell->GetPointId(j))));
      this->BoundaryValues->InsertNextTuple1(static_cast<double>(i));
      }
    }

  Superclass::RequestData(request,inputVector,outputVector);

  this->BoundaryPointIds->Delete();
  this->BoundaryPointIds = NULL;

  this->BoundaryValues->Delete();
  this->BoundaryValues = NULL;

  return 1;
}


<|start_filename|>vtkVmtk/Misc/vtkvmtkLinearToQuadraticMeshFilter.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkLinearToQuadraticMeshFilter.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:47:48 $
Version:   $Revision: 1.6 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkLinearToQuadraticMeshFilter.h"
#include "vtkvmtkGaussQuadrature.h"
#include "vtkvmtkFEShapeFunctions.h"
#include "vtkGeometryFilter.h"
#include "vtkInterpolatingSubdivisionFilter.h"
#include "vtkLinearSubdivisionFilter.h"
#include "vtkButterflySubdivisionFilter.h"
#include "vtkPolyData.h"
#include "vtkCellLocator.h"
#include "vtkUnstructuredGrid.h"
#include "vtkPointData.h"
#include "vtkCellData.h"
#include "vtkCellArray.h"
#include "vtkGenericCell.h"
#include "vtkEdgeTable.h"
#include "vtkIntArray.h"
#include "vtkMath.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkLinearToQuadraticMeshFilter);

vtkvmtkLinearToQuadraticMeshFilter::vtkvmtkLinearToQuadraticMeshFilter()
{
  this->UseBiquadraticWedge = 1;
  this->NumberOfNodesHexahedra = 27;
  this->ReferenceSurface = NULL;
  this->CellEntityIdsArrayName = NULL;
  this->ProjectedCellEntityId = -1;
  this->QuadratureOrder = 10;
  this->NegativeJacobianTolerance = 0.0;
  this->JacobianRelaxation = 1;
  this->TestFinalJacobians = 0;
}

vtkvmtkLinearToQuadraticMeshFilter::~vtkvmtkLinearToQuadraticMeshFilter()
{
  if (this->ReferenceSurface)
    {
    this->ReferenceSurface->Delete();
    this->ReferenceSurface = NULL;
    }

  if (this->CellEntityIdsArrayName)
    {
    delete[] this->CellEntityIdsArrayName;
    this->CellEntityIdsArrayName = NULL;
    }
}

int vtkvmtkLinearToQuadraticMeshFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkUnstructuredGrid *input = vtkUnstructuredGrid::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkIntArray* cellEntityIdsArray = vtkIntArray::New();
  if (this->ReferenceSurface)
    {
    if (this->CellEntityIdsArrayName)
      {
      if (input->GetCellData()->GetArray(this->CellEntityIdsArrayName) == NULL)
        {
        vtkErrorMacro(<< "Error: CellEntityIdsArray with name specified does not exist");
        return 1;
        }
      cellEntityIdsArray->DeepCopy(input->GetCellData()->GetArray(this->CellEntityIdsArrayName));
      }
    }

  vtkPoints* outputPoints = vtkPoints::New();

  int numberOfInputPoints = input->GetNumberOfPoints();

  vtkEdgeTable* edgeTable = vtkEdgeTable::New();
  edgeTable->InitEdgeInsertion(numberOfInputPoints,1);

  vtkEdgeTable* faceTable = vtkEdgeTable::New();
  faceTable->InitEdgeInsertion(numberOfInputPoints,1);

  vtkPointData* inputPointData = input->GetPointData();
  vtkPointData* outputPointData = output->GetPointData();
  outputPointData->InterpolateAllocate(inputPointData,5*numberOfInputPoints);

  vtkCellData* inputCellData = input->GetCellData();
  vtkCellData* outputCellData = output->GetCellData();
  outputCellData->CopyAllocate(inputCellData,numberOfInputPoints);

  int i, j;
  for (i=0; i<numberOfInputPoints; i++)
    {
    outputPoints->InsertNextPoint(input->GetPoint(i));
    outputPointData->CopyData(inputPointData,i,i);
    }

  vtkGenericCell* cell = vtkGenericCell::New();

  vtkIdTypeArray* tetraIds = vtkIdTypeArray::New();
  input->GetIdsOfCellsOfType(VTK_TETRA,tetraIds);

  int numberOfInputTetras = tetraIds->GetNumberOfTuples();

  vtkIdTypeArray* triangleIds = vtkIdTypeArray::New();
  input->GetIdsOfCellsOfType(VTK_TRIANGLE,triangleIds);

  int numberOfInputTriangles = triangleIds->GetNumberOfTuples();

  vtkIdTypeArray* wedgeIds = vtkIdTypeArray::New();
  input->GetIdsOfCellsOfType(VTK_WEDGE,wedgeIds);

  int numberOfInputWedges = wedgeIds->GetNumberOfTuples();

  vtkIdTypeArray* hexahedraIds = vtkIdTypeArray::New();
  input->GetIdsOfCellsOfType(VTK_HEXAHEDRON,hexahedraIds);

  int numberOfInputHexahedra = hexahedraIds->GetNumberOfTuples();

  vtkIdTypeArray* quadIds = vtkIdTypeArray::New();
  input->GetIdsOfCellsOfType(VTK_QUAD,quadIds);

  int numberOfInputQuads = quadIds->GetNumberOfTuples();

  int numberOfInputCells = numberOfInputTetras + numberOfInputTriangles + numberOfInputWedges + numberOfInputHexahedra + numberOfInputQuads;

  output->SetPoints(outputPoints);
  output->Allocate(numberOfInputCells);

  int numberOfCells = input->GetNumberOfCells();
  vtkIdList* inputToOutputCellIds = vtkIdList::New();
  inputToOutputCellIds->SetNumberOfIds(numberOfInputCells);

  for (i=0; i<numberOfCells; i++)
    {
    inputToOutputCellIds->SetId(i,-1);
    }

  vtkIdType cellId;
  double point0[3], point1[3], point2[3], point3[3], point4[3], point5[3], point6[3], point7[3];
  vtkIdType pointId0, pointId1, pointId2, pointId3, pointId4, pointId5, pointId6, pointId7;
  double point[3];
  vtkIdType edgePointId01, edgePointId02, edgePointId03, edgePointId12, edgePointId13, edgePointId23;
  vtkIdType edgePointId14, edgePointId34, edgePointId45, edgePointId35, edgePointId25, edgePointId37;
  vtkIdType edgePointId56, edgePointId67, edgePointId74, edgePointId04, edgePointId15, edgePointId26;
  vtkIdType facePointId0143, facePointId1254, facePointId2035;
  vtkIdType facePointId3047, facePointId1265, facePointId0154, facePointId2376, facePointId0123, facePointId4567;
  vtkIdType midVolumePoint;
  facePointId0143 = facePointId1254 = facePointId2035 = -1;
  facePointId3047 = facePointId1265 = facePointId0154 = facePointId2376 = facePointId0123 = facePointId4567 = -1;
  midVolumePoint = -1;
  vtkIdType neighborCellId;
  vtkIdType pts[27];
  double weights[4];
  double weightsVolume[8];
  weights[0] = weights[1] = weights[2] = weights[3] = 0.25;
  weightsVolume[0] = weightsVolume[1] = weightsVolume[2] = weightsVolume[3] = weightsVolume[4] = weightsVolume[5] = weightsVolume[6] = weightsVolume[7] = 0.125;

  vtkIdList* facePointIds = vtkIdList::New();
  vtkIdList* cellNeighbors = vtkIdList::New();

  for (i=0; i<numberOfInputWedges; i++)
    {
    cellId = wedgeIds->GetValue(i);
    input->GetCell(cellId,cell);

    cell->Points->GetPoint(0,point0);
    cell->Points->GetPoint(1,point1);
    cell->Points->GetPoint(2,point2);
    cell->Points->GetPoint(3,point3);
    cell->Points->GetPoint(4,point4);
    cell->Points->GetPoint(5,point5);

    pointId0 = cell->PointIds->GetId(0);
    pointId1 = cell->PointIds->GetId(1);
    pointId2 = cell->PointIds->GetId(2);
    pointId3 = cell->PointIds->GetId(3);
    pointId4 = cell->PointIds->GetId(4);
    pointId5 = cell->PointIds->GetId(5);

    edgePointId01 = edgeTable->IsEdge(pointId0,pointId1);
    if (edgePointId01 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point1[j]);
        }
      edgePointId01 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId01,pointId0,pointId1,0.5);
      edgeTable->InsertEdge(pointId0,pointId1,edgePointId01);
      }

    edgePointId02 = edgeTable->IsEdge(pointId0,pointId2);
    if (edgePointId02 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point2[j]);
        }
      edgePointId02 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId02,pointId0,pointId2,0.5);
      edgeTable->InsertEdge(pointId0,pointId2,edgePointId02);
      }

    edgePointId12 = edgeTable->IsEdge(pointId1,pointId2);
    if (edgePointId12 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point1[j] + point2[j]);
        }
      edgePointId12 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId12,pointId1,pointId2,0.5);
      edgeTable->InsertEdge(pointId1,pointId2,edgePointId12);
      }

    edgePointId34 = edgeTable->IsEdge(pointId3,pointId4);
    if (edgePointId34 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point3[j] + point4[j]);
        }
      edgePointId34 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId34,pointId3,pointId4,0.5);
      edgeTable->InsertEdge(pointId3,pointId4,edgePointId34);
      }

    edgePointId35 = edgeTable->IsEdge(pointId3,pointId5);
    if (edgePointId35 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point3[j] + point5[j]);
        }
      edgePointId35 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId35,pointId3,pointId5,0.5);
      edgeTable->InsertEdge(pointId3,pointId5,edgePointId35);
      }

    edgePointId45 = edgeTable->IsEdge(pointId4,pointId5);
    if (edgePointId45 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point4[j] + point5[j]);
        }
      edgePointId45 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId45,pointId4,pointId5,0.5);
      edgeTable->InsertEdge(pointId4,pointId5,edgePointId45);
      }

    edgePointId03 = edgeTable->IsEdge(pointId0,pointId3);
    if (edgePointId03 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point3[j]);
        }
      edgePointId03 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId03,pointId0,pointId3,0.5);
      edgeTable->InsertEdge(pointId0,pointId3,edgePointId03);
      }

    edgePointId14 = edgeTable->IsEdge(pointId1,pointId4);
    if (edgePointId14 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point1[j] + point4[j]);
        }
      edgePointId14 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId14,pointId1,pointId4,0.5);
      edgeTable->InsertEdge(pointId1,pointId4,edgePointId14);
      }

    edgePointId25 = edgeTable->IsEdge(pointId2,pointId5);
    if (edgePointId25 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point2[j] + point5[j]);
        }
      edgePointId25 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId25,pointId2,pointId5,0.5);
      edgeTable->InsertEdge(pointId2,pointId5,edgePointId25);
      }

    if (this->UseBiquadraticWedge)
      {
      facePointIds->Initialize();
      facePointIds->InsertNextId(pointId0);
      facePointIds->InsertNextId(pointId1);
      facePointIds->InsertNextId(pointId4);
      facePointIds->InsertNextId(pointId3);
      input->GetCellNeighbors(cellId,facePointIds,cellNeighbors);
      neighborCellId = -1;
      for (j=0; j<cellNeighbors->GetNumberOfIds(); j++)
        {
        if (input->GetCellType(cellNeighbors->GetId(j)) == VTK_WEDGE)
          {
          neighborCellId = cellNeighbors->GetId(j);
          break;
          }
        }
      if (neighborCellId != -1)
        {
        facePointId0143 = faceTable->IsEdge(cellId,neighborCellId);
        if (facePointId0143 == -1)
          {
          for (j=0; j<3; j++)
            {
            point[j] = 0.25 * (point0[j] + point1[j] + point4[j] + point3[j]);
            }
          facePointId0143 = outputPoints->InsertNextPoint(point);
          outputPointData->InterpolatePoint(inputPointData,facePointId0143,facePointIds,weights);
          faceTable->InsertEdge(cellId,neighborCellId,facePointId0143);
          }
        }
  
      facePointIds->Initialize();
      facePointIds->InsertNextId(pointId1);
      facePointIds->InsertNextId(pointId2);
      facePointIds->InsertNextId(pointId5);
      facePointIds->InsertNextId(pointId4);
      input->GetCellNeighbors(cellId,facePointIds,cellNeighbors);
      neighborCellId = -1;
      for (j=0; j<cellNeighbors->GetNumberOfIds(); j++)
        {
        if (input->GetCellType(cellNeighbors->GetId(j)) == VTK_WEDGE)
          {
          neighborCellId = cellNeighbors->GetId(j);
          break;
          }
        }
      if (neighborCellId != -1)
        {
        facePointId1254 = faceTable->IsEdge(cellId,neighborCellId);
        if (facePointId1254 == -1)
          {
          for (j=0; j<3; j++)
            {
            point[j] = 0.25 * (point1[j] + point2[j] + point5[j] + point4[j]);
            }
          facePointId1254 = outputPoints->InsertNextPoint(point);
          outputPointData->InterpolatePoint(inputPointData,facePointId1254,facePointIds,weights);
          faceTable->InsertEdge(cellId,neighborCellId,facePointId1254);
          }
        }
  
      facePointIds->Initialize();
      facePointIds->InsertNextId(pointId2);
      facePointIds->InsertNextId(pointId0);
      facePointIds->InsertNextId(pointId3);
      facePointIds->InsertNextId(pointId5);
      input->GetCellNeighbors(cellId,facePointIds,cellNeighbors);
      neighborCellId = -1;
      for (j=0; j<cellNeighbors->GetNumberOfIds(); j++)
        {
        if (input->GetCellType(cellNeighbors->GetId(j)) == VTK_WEDGE)
          {
          neighborCellId = cellNeighbors->GetId(j);
          break;
          }
        }
      if (neighborCellId != -1)
        {
        facePointId2035 = faceTable->IsEdge(cellId,neighborCellId);
        if (facePointId2035 == -1)
          {
          for (j=0; j<3; j++)
            {
            point[j] = 0.25 * (point2[j] + point0[j] + point3[j] + point5[j]);
            }
          facePointId2035 = outputPoints->InsertNextPoint(point);
          outputPointData->InterpolatePoint(inputPointData,facePointId2035,facePointIds,weights);
          faceTable->InsertEdge(cellId,neighborCellId,facePointId2035);
          }
        }
      }

    pts[0] = pointId0;
    pts[1] = pointId1;
    pts[2] = pointId2;
    pts[3] = pointId3;
    pts[4] = pointId4;
    pts[5] = pointId5;

    pts[6] = edgePointId01;
    pts[7] = edgePointId12;
    pts[8] = edgePointId02;
    pts[9] = edgePointId34;
    pts[10] = edgePointId45;
    pts[11] = edgePointId35;
    pts[12] = edgePointId03;
    pts[13] = edgePointId14;
    pts[14] = edgePointId25;
    pts[15] = facePointId0143;
    pts[16] = facePointId1254;
    pts[17] = facePointId2035;

    vtkIdType newCellId;

#if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0)
    if (this->UseBiquadraticWedge)
      {
      newCellId = output->InsertNextCell(VTK_BIQUADRATIC_QUADRATIC_WEDGE, 18, pts);
      }
    else
      {
      newCellId = output->InsertNextCell(VTK_QUADRATIC_WEDGE, 15, pts);
      }
#else
    newCellId = output->InsertNextCell(VTK_QUADRATIC_WEDGE, 15, pts);
#endif

    inputToOutputCellIds->SetId(cellId,newCellId);
    outputCellData->CopyData(inputCellData,cellId,newCellId);
    }

  for (i=0; i<numberOfInputTetras; i++)
    {
    cellId = tetraIds->GetValue(i);
    input->GetCell(cellId,cell);

    cell->Points->GetPoint(0,point0);
    cell->Points->GetPoint(1,point1);
    cell->Points->GetPoint(2,point2);
    cell->Points->GetPoint(3,point3);

    pointId0 = cell->PointIds->GetId(0);
    pointId1 = cell->PointIds->GetId(1);
    pointId2 = cell->PointIds->GetId(2);
    pointId3 = cell->PointIds->GetId(3);

    edgePointId01 = edgeTable->IsEdge(pointId0,pointId1);
    if (edgePointId01 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point1[j]);
        }
      edgePointId01 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId01,pointId0,pointId1,0.5);
      edgeTable->InsertEdge(pointId0,pointId1,edgePointId01);
      }

    edgePointId02 = edgeTable->IsEdge(pointId0,pointId2);
    if (edgePointId02 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point2[j]);
        }
      edgePointId02 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId02,pointId0,pointId2,0.5);
      edgeTable->InsertEdge(pointId0,pointId2,edgePointId02);
      }

    edgePointId03 = edgeTable->IsEdge(pointId0,pointId3);
    if (edgePointId03 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point3[j]);
        }
      edgePointId03 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId03,pointId0,pointId3,0.5);
      edgeTable->InsertEdge(pointId0,pointId3,edgePointId03);
      }

    edgePointId12 = edgeTable->IsEdge(pointId1,pointId2);
    if (edgePointId12 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point1[j] + point2[j]);
        }
      edgePointId12 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId12,pointId1,pointId2,0.5);
      edgeTable->InsertEdge(pointId1,pointId2,edgePointId12);
      }

    edgePointId13 = edgeTable->IsEdge(pointId1,pointId3);
    if (edgePointId13 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point1[j] + point3[j]);
        }
      edgePointId13 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId13,pointId1,pointId3,0.5);
      edgeTable->InsertEdge(pointId1,pointId3,edgePointId13);
      }

    edgePointId23 = edgeTable->IsEdge(pointId2,pointId3);
    if (edgePointId23 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point2[j] + point3[j]);
        }
      edgePointId23 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId23,pointId2,pointId3,0.5);
      edgeTable->InsertEdge(pointId2,pointId3,edgePointId23);
      }

    pts[0] = pointId0;
    pts[1] = pointId1;
    pts[2] = pointId2;
    pts[3] = pointId3;
    pts[4] = edgePointId01;
    pts[5] = edgePointId12;
    pts[6] = edgePointId02;
    pts[7] = edgePointId03;
    pts[8] = edgePointId13;
    pts[9] = edgePointId23;

    vtkIdType newCellId = output->InsertNextCell(VTK_QUADRATIC_TETRA, 10, pts);

    inputToOutputCellIds->SetId(cellId,newCellId);
    outputCellData->CopyData(inputCellData,cellId,newCellId);
    }

  for (i=0; i<numberOfInputHexahedra; i++)
    {
    cellId = hexahedraIds->GetValue(i);
    input->GetCell(cellId,cell);

    cell->Points->GetPoint(0,point0);
    cell->Points->GetPoint(1,point1);
    cell->Points->GetPoint(2,point2);
    cell->Points->GetPoint(3,point3);
    cell->Points->GetPoint(4,point4);
    cell->Points->GetPoint(5,point5);
    cell->Points->GetPoint(6,point6);
    cell->Points->GetPoint(7,point7);

    pointId0 = cell->PointIds->GetId(0);
    pointId1 = cell->PointIds->GetId(1);
    pointId2 = cell->PointIds->GetId(2);
    pointId3 = cell->PointIds->GetId(3);
    pointId4 = cell->PointIds->GetId(4);
    pointId5 = cell->PointIds->GetId(5);
    pointId6 = cell->PointIds->GetId(6);
    pointId7 = cell->PointIds->GetId(7);

    edgePointId01 = edgeTable->IsEdge(pointId0,pointId1);
    if (edgePointId01 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point1[j]);
        }
      edgePointId01 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId01,pointId0,pointId1,0.5);
      edgeTable->InsertEdge(pointId0,pointId1,edgePointId01);
      }

    edgePointId12 = edgeTable->IsEdge(pointId1,pointId2);
    if (edgePointId12 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point1[j] + point2[j]);
        }
      edgePointId12 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId12,pointId1,pointId2,0.5);
      edgeTable->InsertEdge(pointId1,pointId2,edgePointId12);
      }

    edgePointId23 = edgeTable->IsEdge(pointId2,pointId3);
    if (edgePointId23 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point2[j] + point3[j]);
        }
      edgePointId23 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId23,pointId2,pointId3,0.5);
      edgeTable->InsertEdge(pointId2,pointId3,edgePointId23);
      }

    edgePointId03 = edgeTable->IsEdge(pointId0,pointId3);
    if (edgePointId03 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point3[j]);
        }
      edgePointId03 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId03,pointId0,pointId3,0.5);
      edgeTable->InsertEdge(pointId0,pointId3,edgePointId03);
      }

    edgePointId04 = edgeTable->IsEdge(pointId0,pointId4);
    if (edgePointId04 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point4[j]);
        }
      edgePointId04 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId04,pointId0,pointId4,0.5);
      edgeTable->InsertEdge(pointId0,pointId4,edgePointId04);
      }

    edgePointId15 = edgeTable->IsEdge(pointId1,pointId5);
    if (edgePointId15 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point1[j] + point5[j]);
        }
      edgePointId15 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId15,pointId1,pointId5,0.5);
      edgeTable->InsertEdge(pointId1,pointId5,edgePointId15);
      }

    edgePointId26 = edgeTable->IsEdge(pointId2,pointId6);
    if (edgePointId26 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point2[j] + point6[j]);
        }
      edgePointId26 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId26,pointId2,pointId6,0.5);
      edgeTable->InsertEdge(pointId2,pointId6,edgePointId26);
      }

    edgePointId37 = edgeTable->IsEdge(pointId3,pointId7);
    if (edgePointId37 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point3[j] + point7[j]);
        }
      edgePointId37 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId37,pointId3,pointId7,0.5);
      edgeTable->InsertEdge(pointId3,pointId7,edgePointId37);
      }

    edgePointId45 = edgeTable->IsEdge(pointId4,pointId5);
    if (edgePointId45 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point4[j] + point5[j]);
        }
      edgePointId45 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId45,pointId4,pointId5,0.5);
      edgeTable->InsertEdge(pointId4,pointId5,edgePointId45);
      }

    edgePointId56 = edgeTable->IsEdge(pointId5,pointId6);
    if (edgePointId56 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point5[j] + point6[j]);
        }
      edgePointId56 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId56,pointId5,pointId6,0.5);
      edgeTable->InsertEdge(pointId5,pointId6,edgePointId56);
      }

    edgePointId67 = edgeTable->IsEdge(pointId6,pointId7);
    if (edgePointId67 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point6[j] + point7[j]);
        }
      edgePointId67 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId67,pointId6,pointId7,0.5);
      edgeTable->InsertEdge(pointId6,pointId7,edgePointId67);
      }

    edgePointId74 = edgeTable->IsEdge(pointId4,pointId7);
    if (edgePointId74 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point4[j] + point7[j]);
        }
      edgePointId74 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId74,pointId4,pointId7,0.5);
      edgeTable->InsertEdge(pointId4,pointId7,edgePointId74);
      }

    if (this->NumberOfNodesHexahedra > 20)
      {

      facePointIds->Initialize();
      facePointIds->InsertNextId(pointId0);
      facePointIds->InsertNextId(pointId1);
      facePointIds->InsertNextId(pointId5);
      facePointIds->InsertNextId(pointId4);
      input->GetCellNeighbors(cellId,facePointIds,cellNeighbors);
      facePointId0154 = -1;
      if (cellNeighbors->GetNumberOfIds() == 0)
        {
        neighborCellId = numberOfInputCells + 1;
        }
      else
        {
        neighborCellId = -1;
        }
      for (j=0; j<cellNeighbors->GetNumberOfIds(); j++)
        {
        if (input->GetCellType(cellNeighbors->GetId(j)) == VTK_HEXAHEDRON ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_QUAD ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_TRIQUADRATIC_HEXAHEDRON ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_BIQUADRATIC_QUAD)
          {
          neighborCellId = cellNeighbors->GetId(j);
          break;
          }
        }
      if (neighborCellId != -1)
        {
        facePointId0154 = faceTable->IsEdge(cellId,neighborCellId);
        if (facePointId0154 == -1)
          {
          for (j=0; j<3; j++)
            {
            point[j] = 0.25 * (point0[j] + point1[j] + point5[j] + point4[j]);
            }
          facePointId0154 = outputPoints->InsertNextPoint(point);
          outputPointData->InterpolatePoint(inputPointData,facePointId0154,facePointIds,weights);
          faceTable->InsertEdge(cellId,neighborCellId,facePointId0154);
          }
        }

      facePointIds->Initialize();
      facePointIds->InsertNextId(pointId1);
      facePointIds->InsertNextId(pointId2);
      facePointIds->InsertNextId(pointId6);
      facePointIds->InsertNextId(pointId5);
      input->GetCellNeighbors(cellId,facePointIds,cellNeighbors);
      facePointId1265 = -1;
      if (cellNeighbors->GetNumberOfIds() == 0)
        {
        neighborCellId = numberOfInputCells + 2;
        }
      else
        {
        neighborCellId = -1;
        }
      for (j=0; j<cellNeighbors->GetNumberOfIds(); j++)
        {
        if (input->GetCellType(cellNeighbors->GetId(j)) == VTK_HEXAHEDRON ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_QUAD ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_TRIQUADRATIC_HEXAHEDRON ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_BIQUADRATIC_QUAD)
          {
          neighborCellId = cellNeighbors->GetId(j);
          break;
          }
        }
      if (neighborCellId != -1)
        {
        facePointId1265 = faceTable->IsEdge(cellId,neighborCellId);
        if (facePointId1265 == -1)
          {
          for (j=0; j<3; j++)
            {
            point[j] = 0.25 * (point1[j] + point2[j] + point6[j] + point5[j]);
            }
          facePointId1265 = outputPoints->InsertNextPoint(point);
          outputPointData->InterpolatePoint(inputPointData,facePointId1265,facePointIds,weights);
          faceTable->InsertEdge(cellId,neighborCellId,facePointId1265);
          }
        }

      facePointIds->Initialize();
      facePointIds->InsertNextId(pointId2);
      facePointIds->InsertNextId(pointId3);
      facePointIds->InsertNextId(pointId7);
      facePointIds->InsertNextId(pointId6);
      input->GetCellNeighbors(cellId,facePointIds,cellNeighbors);
      facePointId2376 = -1;
      if (cellNeighbors->GetNumberOfIds() == 0)
        {
        neighborCellId = numberOfInputCells + 3;
        }
      else
        {
        neighborCellId = -1;
        }
      for (j=0; j<cellNeighbors->GetNumberOfIds(); j++)
        {
        if (input->GetCellType(cellNeighbors->GetId(j)) == VTK_HEXAHEDRON ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_QUAD ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_TRIQUADRATIC_HEXAHEDRON ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_BIQUADRATIC_QUAD)
          {
          neighborCellId = cellNeighbors->GetId(j);
          break;
          }
        }
      if (neighborCellId != -1)
        {
        facePointId2376 = faceTable->IsEdge(cellId,neighborCellId);
        if (facePointId2376 == -1)
          {
          for (j=0; j<3; j++)
            {
            point[j] = 0.25 * (point2[j] + point3[j] + point7[j] + point6[j]);
            }
          facePointId2376 = outputPoints->InsertNextPoint(point);
          outputPointData->InterpolatePoint(inputPointData,facePointId2376,facePointIds,weights);
          faceTable->InsertEdge(cellId,neighborCellId,facePointId2376);
          }
        }

      facePointIds->Initialize();
      facePointIds->InsertNextId(pointId3);
      facePointIds->InsertNextId(pointId0);
      facePointIds->InsertNextId(pointId4);
      facePointIds->InsertNextId(pointId7);
      input->GetCellNeighbors(cellId,facePointIds,cellNeighbors);
      facePointId3047 = -1;
      if (cellNeighbors->GetNumberOfIds() == 0)
        {
        neighborCellId = numberOfInputCells + 4;
        }
      else
        {
        neighborCellId = -1;
        }
      for (j=0; j<cellNeighbors->GetNumberOfIds(); j++)
        {
        if (input->GetCellType(cellNeighbors->GetId(j)) == VTK_HEXAHEDRON ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_QUAD ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_TRIQUADRATIC_HEXAHEDRON ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_BIQUADRATIC_QUAD)
          {
          neighborCellId = cellNeighbors->GetId(j);
          break;
          }
        }
      if (neighborCellId != -1)
        {
        facePointId3047 = faceTable->IsEdge(cellId,neighborCellId);
        if (facePointId3047 == -1)
          {
          for (j=0; j<3; j++)
            {
            point[j] = 0.25 * (point3[j] + point0[j] + point4[j] + point7[j]);
            }
          facePointId3047 = outputPoints->InsertNextPoint(point);
          outputPointData->InterpolatePoint(inputPointData,facePointId3047,facePointIds,weights);
          faceTable->InsertEdge(cellId,neighborCellId,facePointId3047);
          }
        }

      if (this->NumberOfNodesHexahedra > 24)
        {

        facePointIds->Initialize();
        facePointIds->InsertNextId(pointId0);
        facePointIds->InsertNextId(pointId1);
        facePointIds->InsertNextId(pointId2);
        facePointIds->InsertNextId(pointId3);
        input->GetCellNeighbors(cellId,facePointIds,cellNeighbors);
        facePointId0123 = -1;
        if (cellNeighbors->GetNumberOfIds() == 0)
          {
          neighborCellId = numberOfInputCells + 5;
          }
        else
          {
          neighborCellId = -1;
          }
        for (j=0; j<cellNeighbors->GetNumberOfIds(); j++)
          {
          if (input->GetCellType(cellNeighbors->GetId(j)) == VTK_HEXAHEDRON ||
              input->GetCellType(cellNeighbors->GetId(j)) == VTK_QUAD ||
              input->GetCellType(cellNeighbors->GetId(j)) == VTK_TRIQUADRATIC_HEXAHEDRON ||
              input->GetCellType(cellNeighbors->GetId(j)) == VTK_BIQUADRATIC_QUAD)
            {
            neighborCellId = cellNeighbors->GetId(j);
            break;
            }
          }
        if (neighborCellId != -1)
          {
          facePointId0123 = faceTable->IsEdge(cellId,neighborCellId);
          if (facePointId0123 == -1)
            {
            for (j=0; j<3; j++)
              {
              point[j] = 0.25 * (point0[j] + point1[j] + point2[j] + point3[j]);
              }
            facePointId0123 = outputPoints->InsertNextPoint(point);
            outputPointData->InterpolatePoint(inputPointData,facePointId0123,facePointIds,weights);
            faceTable->InsertEdge(cellId,neighborCellId,facePointId0123);
            }
          }

        facePointIds->Initialize();
        facePointIds->InsertNextId(pointId4);
        facePointIds->InsertNextId(pointId5);
        facePointIds->InsertNextId(pointId6);
        facePointIds->InsertNextId(pointId7);
        input->GetCellNeighbors(cellId,facePointIds,cellNeighbors);
        facePointId4567 = -1;
        if (cellNeighbors->GetNumberOfIds() == 0)
          {
          neighborCellId = numberOfInputCells + 6;
          }
        else
          {
          neighborCellId = -1;
          }
        for (j=0; j<cellNeighbors->GetNumberOfIds(); j++)
          {
          if (input->GetCellType(cellNeighbors->GetId(j)) == VTK_HEXAHEDRON ||
              input->GetCellType(cellNeighbors->GetId(j)) == VTK_QUAD ||
              input->GetCellType(cellNeighbors->GetId(j)) == VTK_TRIQUADRATIC_HEXAHEDRON ||
              input->GetCellType(cellNeighbors->GetId(j)) == VTK_BIQUADRATIC_QUAD)
            {
            neighborCellId = cellNeighbors->GetId(j);
            break;
            }
          }
        if (neighborCellId != -1)
          {
          facePointId4567 = faceTable->IsEdge(cellId,neighborCellId);
          if (facePointId4567 == -1)
            {
            for (j=0; j<3; j++)
              {
              point[j] = 0.25 * (point4[j] + point5[j] + point6[j] + point7[j]);
              }
            facePointId4567 = outputPoints->InsertNextPoint(point);
            outputPointData->InterpolatePoint(inputPointData,facePointId4567,facePointIds,weights);
            faceTable->InsertEdge(cellId,neighborCellId,facePointId4567);
            }
          }

        facePointIds->Initialize();
        facePointIds->InsertNextId(pointId0);
        facePointIds->InsertNextId(pointId1);
        facePointIds->InsertNextId(pointId2);
        facePointIds->InsertNextId(pointId3);
        facePointIds->InsertNextId(pointId4);
        facePointIds->InsertNextId(pointId5);
        facePointIds->InsertNextId(pointId6);
        facePointIds->InsertNextId(pointId7);
        for (j=0; j<3; j++)
          {
          point[j] = 0.125 * (point0[j] + point1[j] + point2[j] + point3[j] + point4[j] + point5[j] + point6[j] + point7[j]);
          }
        midVolumePoint = outputPoints->InsertNextPoint(point);
        outputPointData->InterpolatePoint(inputPointData,midVolumePoint,facePointIds,weightsVolume);
        }
      }

    pts[0] = pointId0;
    pts[1] = pointId1;
    pts[2] = pointId2;
    pts[3] = pointId3;
    pts[4] = pointId4;
    pts[5] = pointId5;
    pts[6] = pointId6;
    pts[7] = pointId7;
    pts[8] = edgePointId01;
    pts[9] = edgePointId12;
    pts[10] = edgePointId23;
    pts[11] = edgePointId03;
    pts[12] = edgePointId45;
    pts[13] = edgePointId56;
    pts[14] = edgePointId67;
    pts[15] = edgePointId74;
    pts[16] = edgePointId04;
    pts[17] = edgePointId15;
    pts[18] = edgePointId26;
    pts[19] = edgePointId37;

    if (this->NumberOfNodesHexahedra > 20)
      {
      pts[20] = facePointId3047;
      pts[21] = facePointId1265;
      pts[22] = facePointId0154;
      pts[23] = facePointId2376;
      if (this->NumberOfNodesHexahedra > 24)
        {
        pts[24] = facePointId0123;
        pts[25] = facePointId4567;
        pts[26] = midVolumePoint;
        }
      }

    vtkIdType newCellId;

    switch (this->NumberOfNodesHexahedra)
      {
      case 20:
        {
          newCellId = output->InsertNextCell(VTK_QUADRATIC_HEXAHEDRON, 20, pts);
          break;
        }
      case 24:
        {
          newCellId = output->InsertNextCell(VTK_BIQUADRATIC_QUADRATIC_HEXAHEDRON, 24, pts);
          break;
        }
      case 27:
        {
          newCellId = output->InsertNextCell(VTK_TRIQUADRATIC_HEXAHEDRON, 27, pts);
          break;
        }
      default:
        {
          newCellId = output->InsertNextCell(VTK_HEXAHEDRON, 8, pts);
          vtkErrorMacro(<<"Invalid number of nodes for a quadratic hexahedral mesh- choose 20, 24, or 27.");
          return 1;
        }
      }

    inputToOutputCellIds->SetId(cellId,newCellId);
    outputCellData->CopyData(inputCellData,cellId,newCellId);
    }

  vtkCellLocator* locator = NULL;
  if (this->ReferenceSurface)
    {
    locator = vtkCellLocator::New();
    locator->SetDataSet(this->ReferenceSurface);
    locator->BuildLocator();
    }

  double projectedPoint[3];
  vtkIdType referenceCellId;
  int subId;
  double dist2;

  vtkEdgeTable* surfaceEdgeTable = vtkEdgeTable::New();
  vtkEdgeTable* surfaceFaceTable = vtkEdgeTable::New();
  surfaceEdgeTable->InitEdgeInsertion(numberOfInputPoints,1);
  surfaceFaceTable->InitEdgeInsertion(numberOfInputPoints,1);

  for (i=0; i<numberOfInputTriangles; i++)
    {
    cellId = triangleIds->GetValue(i);
    input->GetCell(cellId,cell);

    bool project = true;
    if (locator)
      {
      if (this->CellEntityIdsArrayName) 
        {
        if (cellEntityIdsArray->GetValue(cellId) != this->ProjectedCellEntityId)
          {
          project = false;
          }
        }
      }

    cell->Points->GetPoint(0,point0);
    cell->Points->GetPoint(1,point1);
    cell->Points->GetPoint(2,point2);

    pointId0 = cell->PointIds->GetId(0);
    pointId1 = cell->PointIds->GetId(1);
    pointId2 = cell->PointIds->GetId(2);

    edgePointId01 = edgeTable->IsEdge(pointId0,pointId1);
    if (edgePointId01 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point1[j]);
        }
      edgePointId01 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId01,pointId0,pointId1,0.5);
      edgeTable->InsertEdge(pointId0,pointId1,edgePointId01);
      }

    edgePointId02 = edgeTable->IsEdge(pointId0,pointId2);
    if (edgePointId02 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point2[j]);
        }
      edgePointId02 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId02,pointId0,pointId2,0.5);
      edgeTable->InsertEdge(pointId0,pointId2,edgePointId02);
      }

    edgePointId12 = edgeTable->IsEdge(pointId1,pointId2);
    if (edgePointId12 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point1[j] + point2[j]);
        }
      edgePointId12 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId12,pointId1,pointId2,0.5);
      edgeTable->InsertEdge(pointId1,pointId2,edgePointId12);
      }

    if (project)
      {
      surfaceEdgeTable->InsertEdge(pointId0,pointId1,edgePointId01);
      surfaceEdgeTable->InsertEdge(pointId0,pointId2,edgePointId02);
      surfaceEdgeTable->InsertEdge(pointId1,pointId2,edgePointId12);
      }

    pts[0] = pointId0;
    pts[1] = pointId1;
    pts[2] = pointId2;
    pts[3] = edgePointId01;
    pts[4] = edgePointId12;
    pts[5] = edgePointId02;

    vtkIdType newCellId = output->InsertNextCell(VTK_QUADRATIC_TRIANGLE, 6, pts);

    inputToOutputCellIds->SetId(cellId,newCellId);
    outputCellData->CopyData(inputCellData,cellId,newCellId);

    if (locator && project)
      {
      double point01[3], point12[3], point02[3];
      outputPoints->GetPoint(edgePointId01,point01);
      locator->FindClosestPoint(point01,projectedPoint,referenceCellId,subId,dist2);
      outputPoints->SetPoint(edgePointId01,projectedPoint);
      outputPoints->GetPoint(edgePointId12,point12);
      locator->FindClosestPoint(point12,projectedPoint,referenceCellId,subId,dist2);
      outputPoints->SetPoint(edgePointId12,projectedPoint);
      outputPoints->GetPoint(edgePointId02,point02);
      locator->FindClosestPoint(point02,projectedPoint,referenceCellId,subId,dist2);
      outputPoints->SetPoint(edgePointId02,projectedPoint);
      }
    }

  for (i=0; i<numberOfInputQuads; i++)
    {
    cellId = quadIds->GetValue(i);
    input->GetCell(cellId,cell);

    bool project = true;
    if (locator)
      {
      if (this->CellEntityIdsArrayName) 
        {
        if (cellEntityIdsArray->GetValue(cellId) != this->ProjectedCellEntityId)
          {
          project = false;
          }
        }
      }

    cell->Points->GetPoint(0,point0);
    cell->Points->GetPoint(1,point1);
    cell->Points->GetPoint(2,point2);
    cell->Points->GetPoint(3,point3);

    pointId0 = cell->PointIds->GetId(0);
    pointId1 = cell->PointIds->GetId(1);
    pointId2 = cell->PointIds->GetId(2);
    pointId3 = cell->PointIds->GetId(3);

    edgePointId01 = edgeTable->IsEdge(pointId0,pointId1);
    if (edgePointId01 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point1[j]);
        }
      edgePointId01 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId01,pointId0,pointId1,0.5);
      edgeTable->InsertEdge(pointId0,pointId1,edgePointId01);
      }

    edgePointId12 = edgeTable->IsEdge(pointId1,pointId2);
    if (edgePointId12 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point1[j] + point2[j]);
        }
      edgePointId12 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId12,pointId1,pointId2,0.5);
      edgeTable->InsertEdge(pointId1,pointId2,edgePointId12);
      }

    edgePointId23 = edgeTable->IsEdge(pointId2,pointId3);
    if (edgePointId23 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point2[j] + point3[j]);
        }
      edgePointId23 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId23,pointId2,pointId3,0.5);
      edgeTable->InsertEdge(pointId2,pointId3,edgePointId23);
      }

    edgePointId03 = edgeTable->IsEdge(pointId0,pointId3);
    if (edgePointId03 == -1)
      {
      for (j=0; j<3; j++)
        {
        point[j] = 0.5 * (point0[j] + point3[j]);
        }
      edgePointId03 = outputPoints->InsertNextPoint(point);
      outputPointData->InterpolateEdge(inputPointData,edgePointId03,pointId0,pointId3,0.5);
      edgeTable->InsertEdge(pointId0,pointId3,edgePointId03);
      }

    if (project)
      {
      surfaceEdgeTable->InsertEdge(pointId0,pointId1,edgePointId01);
      surfaceEdgeTable->InsertEdge(pointId1,pointId2,edgePointId12);
      surfaceEdgeTable->InsertEdge(pointId2,pointId3,edgePointId23);
      surfaceEdgeTable->InsertEdge(pointId0,pointId3,edgePointId03);
      }

    pts[0] = pointId0;
    pts[1] = pointId1;
    pts[2] = pointId2;
    pts[3] = pointId3;
    pts[4] = edgePointId01;
    pts[5] = edgePointId12;
    pts[6] = edgePointId23;
    pts[7] = edgePointId03;

    if (this->NumberOfNodesHexahedra > 20)
      {
      facePointIds->Initialize();
      facePointIds->InsertNextId(pointId0);
      facePointIds->InsertNextId(pointId1);
      facePointIds->InsertNextId(pointId2);
      facePointIds->InsertNextId(pointId3);
      input->GetCellNeighbors(cellId,facePointIds,cellNeighbors);
      neighborCellId = -1;
      for (j=0; j<cellNeighbors->GetNumberOfIds(); j++)
        {
        if (input->GetCellType(cellNeighbors->GetId(j)) == VTK_TRIQUADRATIC_HEXAHEDRON ||
            input->GetCellType(cellNeighbors->GetId(j)) == VTK_HEXAHEDRON)
          {
          neighborCellId = cellNeighbors->GetId(j);
          facePointId0123 = faceTable->IsEdge(cellId,neighborCellId);
          break;
          }
        }
      if (neighborCellId != -1)
        {
        pts[8] = facePointId0123;
        if (project)
          {
          surfaceFaceTable->InsertEdge(cellId,neighborCellId,facePointId0123);
          }
        }
      }

    vtkIdType newCellId;
    switch (this->NumberOfNodesHexahedra)
      {
      case 20:
        {
          newCellId = output->InsertNextCell(VTK_QUADRATIC_QUAD, 8, pts);
          break;
        }
      case 27:
        {
          newCellId = output->InsertNextCell(VTK_BIQUADRATIC_QUAD, 9, pts);
          break;
        }
      default:
        {
          newCellId = output->InsertNextCell(VTK_QUAD, 4, pts);
          vtkErrorMacro(<<"Invalid number of nodes (" << this->NumberOfNodesHexahedra << ") for a hexahedral mesh with quadratic quad surface- choose 20 or 27.\n");
          return 1;
        }
      }

    inputToOutputCellIds->SetId(cellId,newCellId);
    outputCellData->CopyData(inputCellData,cellId,newCellId);

    if (locator && project)
      {
      double point01[3], point12[3], point23[3], point03[3], facePoint[3];
      outputPoints->GetPoint(edgePointId01,point01);
      locator->FindClosestPoint(point01,projectedPoint,referenceCellId,subId,dist2);
      outputPoints->SetPoint(edgePointId01,projectedPoint);
      outputPoints->GetPoint(edgePointId12,point12);
      locator->FindClosestPoint(point12,projectedPoint,referenceCellId,subId,dist2);
      outputPoints->SetPoint(edgePointId12,projectedPoint);
      outputPoints->GetPoint(edgePointId23,point23);
      locator->FindClosestPoint(point23,projectedPoint,referenceCellId,subId,dist2);
      outputPoints->SetPoint(edgePointId23,projectedPoint);
      outputPoints->GetPoint(edgePointId03,point03);
      locator->FindClosestPoint(point03,projectedPoint,referenceCellId,subId,dist2);
      outputPoints->SetPoint(edgePointId03,projectedPoint);
      if (this->NumberOfNodesHexahedra > 20)
        {
        outputPoints->GetPoint(facePointId0123,facePoint);
        locator->FindClosestPoint(facePoint,projectedPoint,referenceCellId,subId,dist2);
        outputPoints->SetPoint(facePointId0123,projectedPoint);
        }
      }
    }

//#define LEGACY_RELAXATION
#ifdef LEGACY_RELAXATION
  int numberOfRelaxationSteps = 10;
  int maxSignChangeIterations = 20;
  int signChangeCounter = 0;
  bool anySignChange = true;
  while (anySignChange)
    {
    if (signChangeCounter >= maxSignChangeIterations)
      {
      break;
      }
    signChangeCounter++;
    anySignChange = false;
    for (i=0; i<numberOfInputTriangles; i++)
      {
      cellId = triangleIds->GetValue(i);
      input->GetCell(cellId,cell);
  
      cell->Points->GetPoint(0,point0);
      cell->Points->GetPoint(1,point1);
      cell->Points->GetPoint(2,point2);
  
      pointId0 = cell->PointIds->GetId(0);
      pointId1 = cell->PointIds->GetId(1);
      pointId2 = cell->PointIds->GetId(2);
  
      edgePointId01 = edgeTable->IsEdge(pointId0,pointId1);
      edgePointId12 = edgeTable->IsEdge(pointId1,pointId2);
      edgePointId02 = edgeTable->IsEdge(pointId0,pointId2);
   
      if (locator)
        {
        bool project = true;
        if (this->CellEntityIdsArrayName) 
          {
          if (cellEntityIdsArray->GetValue(cellId) != this->ProjectedCellEntityId)
            {
            project = false;
            }
          }

        if (project)
          {
          vtkIdType volumeCellId = -1;
          vtkIdList* volumeCellIds = vtkIdList::New();
          output->GetCellNeighbors(cellId,cell->PointIds,volumeCellIds);
          if (volumeCellIds->GetNumberOfIds() == 0)
            {
            vtkWarningMacro(<<"Warning: surface element "<<cellId<<" does not have a volume element attached.");
            volumeCellIds->Delete();
            continue;
            }
          if (volumeCellIds->GetNumberOfIds() > 1)
            {
            vtkWarningMacro(<<"Warning: surface element "<<cellId<<" has more than one volume element attached.");
            volumeCellIds->Delete();
            continue;
            }
          volumeCellId = volumeCellIds->GetId(0);
          vtkCell* linearVolumeCell = input->GetCell(volumeCellId);
          vtkCell* quadraticVolumeCell = output->GetCell(volumeCellId);
          double point01[3], point12[3], point02[3];
          double projectedPoint01[3], projectedPoint12[3], projectedPoint02[3];
          outputPoints->GetPoint(edgePointId01,projectedPoint01);
          outputPoints->GetPoint(edgePointId12,projectedPoint12);
          outputPoints->GetPoint(edgePointId02,projectedPoint02);
          int s;
          for (s=0; s<numberOfRelaxationSteps; s++)
            {
            if (!this->HasJacobianChangedSign(linearVolumeCell,quadraticVolumeCell))
              {
              break;
              }
            anySignChange = true;
            vtkWarningMacro(<<"Warning: projection causes element "<<volumeCellId<<" to have a negative Jacobian somewhere. Relaxing projection for this element.");
            double relaxation = (double)(s+1)/(double)numberOfRelaxationSteps;
            for (j=0; j<3; j++)
              {
              point01[j] = (1.0 - relaxation) * projectedPoint01[j] + relaxation * (0.5 * (point0[j] + point1[j]));
              point12[j] = (1.0 - relaxation) * projectedPoint12[j] + relaxation * (0.5 * (point1[j] + point2[j]));
              point02[j] = (1.0 - relaxation) * projectedPoint02[j] + relaxation * (0.5 * (point0[j] + point2[j]));
              }
            outputPoints->SetPoint(edgePointId01,point01);
            outputPoints->SetPoint(edgePointId12,point12);
            outputPoints->SetPoint(edgePointId02,point02);
            quadraticVolumeCell = output->GetCell(volumeCellId);
            }
          volumeCellIds->Delete();
          }
        }
      }

    for (i=0; i<numberOfInputQuads; i++)
      {
      cellId = quadIds->GetValue(i);
      input->GetCell(cellId,cell);

      cell->Points->GetPoint(0,point0);
      cell->Points->GetPoint(1,point1);
      cell->Points->GetPoint(2,point2);
      cell->Points->GetPoint(3,point3);

      pointId0 = cell->PointIds->GetId(0);
      pointId1 = cell->PointIds->GetId(1);
      pointId2 = cell->PointIds->GetId(2);
      pointId3 = cell->PointIds->GetId(3);

      edgePointId01 = edgeTable->IsEdge(pointId0,pointId1);
      edgePointId12 = edgeTable->IsEdge(pointId1,pointId2);
      edgePointId23 = edgeTable->IsEdge(pointId2,pointId3);
      edgePointId03 = edgeTable->IsEdge(pointId0,pointId3);

      if (locator)
        {
        bool project = true;
        if (this->CellEntityIdsArrayName) 
          {
          if (cellEntityIdsArray->GetValue(cellId) != this->ProjectedCellEntityId)
            {
            project = false;
            }
          }
        if (project)
          {
          vtkIdType volumeCellId = 0;
          vtkIdList* volumeCellIds = vtkIdList::New();
          output->GetCellNeighbors(cellId,cell->PointIds,volumeCellIds);
          if (volumeCellIds->GetNumberOfIds() == 0)
            {
            vtkWarningMacro(<<"Warning: surface element "<<cellId<<" does not have a volume element attached.");
            volumeCellIds->Delete();
            continue;
            }
          if (volumeCellIds->GetNumberOfIds() > 1)
            {
            vtkWarningMacro(<<"Warning: surface element "<<cellId<<" has more than one volume element attached.");
            volumeCellIds->Delete();
            continue;
            }
          volumeCellId = volumeCellIds->GetId(0);
          vtkCell* linearVolumeCell = input->GetCell(volumeCellId);
          vtkCell* quadraticVolumeCell = output->GetCell(volumeCellId);
          double point01[3], point12[3], point23[3], point03[3];
          double projectedPoint01[3], projectedPoint12[3], projectedPoint23[3], projectedPoint03[3];
          outputPoints->GetPoint(edgePointId01,projectedPoint01);
          outputPoints->GetPoint(edgePointId12,projectedPoint12);
          outputPoints->GetPoint(edgePointId23,projectedPoint23);
          outputPoints->GetPoint(edgePointId03,projectedPoint03);

          int s;
          for (s=0; s<numberOfRelaxationSteps; s++)
            {
            if (!this->HasJacobianChangedSign(linearVolumeCell,quadraticVolumeCell))
              {
              break;
              }
            anySignChange = true;
            vtkWarningMacro(<<"Warning: projection causes element "<<volumeCellId<<" to have a negative Jacobian somewhere. Relaxing projection for this element.");
            double relaxation = (double)(s+1)/(double)numberOfRelaxationSteps;
            for (j=0; j<3; j++)
              {
              point01[j] = (1.0 - relaxation) * projectedPoint01[j] + relaxation * (0.5 * (point0[j] + point1[j]));
              point12[j] = (1.0 - relaxation) * projectedPoint12[j] + relaxation * (0.5 * (point1[j] + point2[j]));
              point23[j] = (1.0 - relaxation) * projectedPoint23[j] + relaxation * (0.5 * (point2[j] + point3[j]));
              point03[j] = (1.0 - relaxation) * projectedPoint03[j] + relaxation * (0.5 * (point0[j] + point3[j]));
              }
            outputPoints->SetPoint(edgePointId01,point01);
            outputPoints->SetPoint(edgePointId12,point12);
            outputPoints->SetPoint(edgePointId23,point23);
            outputPoints->SetPoint(edgePointId03,point03);
            quadraticVolumeCell = output->GetCell(volumeCellId);
            }
          volumeCellIds->Delete();
          }
        }
      }
    }
#else
  int numberOfRelaxationSteps = 10;
  int maxSignChangeIterations = 20;
  int signChangeCounter = 0;
  bool anySignChange = true;
  if (!locator)
    {
    anySignChange = false;
    }
  while (anySignChange)
    {
    if (signChangeCounter >= maxSignChangeIterations)
      {
      break;
      }
    signChangeCounter++;
    anySignChange = false;

    surfaceEdgeTable->InitTraversal();
    vtkIdType edgePointId = surfaceEdgeTable->GetNextEdge(pointId0,pointId1);
    vtkIdList* edgePointIds = vtkIdList::New();
    vtkIdList* cellEdgeNeighbors = vtkIdList::New();
    while (edgePointId >= 0)
      {
      edgePointIds->Initialize();
      edgePointIds->InsertNextId(pointId0);
      edgePointIds->InsertNextId(pointId1);
      input->GetCellNeighbors(-1,edgePointIds,cellEdgeNeighbors);
      int numberOfCellEdgeNeighbors = cellEdgeNeighbors->GetNumberOfIds();
      for (i=0; i<numberOfCellEdgeNeighbors; i++)
        {
        vtkIdType volumeCellId = cellEdgeNeighbors->GetId(i);
        if (input->GetCell(volumeCellId)->GetCellDimension() != 3)
          {
          continue;
          }
        vtkCell* linearVolumeCell = input->GetCell(volumeCellId);
        vtkIdType outputCellId = inputToOutputCellIds->GetId(volumeCellId);
        if (outputCellId == -1)
          {
          continue;
          }
        vtkCell* quadraticVolumeCell = output->GetCell(outputCellId);

        int s;
        for (s=0; s<numberOfRelaxationSteps; s++)
          {
          if (!this->HasJacobianChangedSign(linearVolumeCell,quadraticVolumeCell))
            {
            break;
            }
          anySignChange = true;
          vtkWarningMacro(<<"Warning: projection causes element "<<volumeCellId<<" to have a negative Jacobian somewhere. Relaxing projection for this element.");
          double relaxation = (double)(s+1)/(double)numberOfRelaxationSteps;
          int numberOfEdges = linearVolumeCell->GetNumberOfEdges();
          int e;
          for (e=0; e<numberOfEdges; e++)
            {
            vtkCell* edge = linearVolumeCell->GetEdge(e);
            vtkIdType pointId0 = edge->GetPointId(0);
            vtkIdType pointId1 = edge->GetPointId(1);
            vtkIdType edgePointId = surfaceEdgeTable->IsEdge(pointId0,pointId1);
            if (edgePointId == -1)
              {
              continue;
              }
            double edgePoint[3], relaxedEdgePoint[3];
            input->GetPoint(pointId0,point0);
            input->GetPoint(pointId1,point1);
            output->GetPoint(edgePointId,edgePoint);
            for (j=0; j<3; j++)
              {
              relaxedEdgePoint[j] = (1.0 - relaxation) * edgePoint[j] + relaxation * (0.5 * (point0[j] + point1[j]));
              }
            outputPoints->SetPoint(edgePointId,relaxedEdgePoint);
            }
          quadraticVolumeCell = output->GetCell(outputCellId);
          }
        }
      edgePointId = surfaceEdgeTable->GetNextEdge(pointId0,pointId1);
      }
    edgePointIds->Delete();
    cellEdgeNeighbors->Delete();
    }
#endif

  // Legacy relaxation for non-edge points on surface faces
  if (numberOfInputQuads > 0 && this->NumberOfNodesHexahedra > 20)
    {
    int numberOfRelaxationSteps = 10;
    int maxSignChangeIterations = 20;
    int signChangeCounter = 0;
    bool anySignChange = true;
    while (anySignChange)
      {
      if (signChangeCounter >= maxSignChangeIterations)
        {
        break;
        }
      signChangeCounter++;
      anySignChange = false;

      for (i=0; i<numberOfInputQuads; i++)
        {
        cellId = quadIds->GetValue(i);
        input->GetCell(cellId,cell);

        cell->Points->GetPoint(0,point0);
        cell->Points->GetPoint(1,point1);
        cell->Points->GetPoint(2,point2);
        cell->Points->GetPoint(3,point3);

        pointId0 = cell->PointIds->GetId(0);
        pointId1 = cell->PointIds->GetId(1);
        pointId2 = cell->PointIds->GetId(2);
        pointId3 = cell->PointIds->GetId(3);

        facePointIds->Initialize();
        facePointIds->InsertNextId(pointId0);
        facePointIds->InsertNextId(pointId1);
        facePointIds->InsertNextId(pointId2);
        facePointIds->InsertNextId(pointId3);
        input->GetCellNeighbors(cellId,facePointIds,cellNeighbors);
        neighborCellId = -1;
        facePointId0123 = -1;
        for (j=0; j<cellNeighbors->GetNumberOfIds(); j++)
          {
          if (input->GetCellType(cellNeighbors->GetId(j)) == VTK_TRIQUADRATIC_HEXAHEDRON ||
              input->GetCellType(cellNeighbors->GetId(j)) == VTK_HEXAHEDRON)
            {
            neighborCellId = cellNeighbors->GetId(j);
            facePointId0123 = faceTable->IsEdge(cellId,neighborCellId);
            break;
            }
          }
        if (locator)
          {
          bool project = true;
          if (this->CellEntityIdsArrayName) 
            {
            if (cellEntityIdsArray->GetValue(cellId) != this->ProjectedCellEntityId)
              {
              project = false;
              }
            }
          if (project)
            {
            vtkIdType volumeCellId = 0;
            vtkIdList* volumeCellIds = vtkIdList::New();
            output->GetCellNeighbors(cellId,cell->PointIds,volumeCellIds);
            if (volumeCellIds->GetNumberOfIds() == 0)
              {
              vtkWarningMacro(<<"Warning: surface element "<<cellId<<" does not have a volume element attached.");
              volumeCellIds->Delete();
              continue;
              }
            if (volumeCellIds->GetNumberOfIds() > 1)
              {
              vtkWarningMacro(<<"Warning: surface element "<<cellId<<" has more than one volume element attached.");
              volumeCellIds->Delete();
              continue;
              }
            volumeCellId = volumeCellIds->GetId(0);
            vtkCell* linearVolumeCell = input->GetCell(volumeCellId);
            vtkCell* quadraticVolumeCell = output->GetCell(volumeCellId);
            double facePoint[3];
            double projectedFacePoint0123[3];

            outputPoints->GetPoint(facePointId0123,projectedFacePoint0123);
            int s;
            for (s=0; s<numberOfRelaxationSteps; s++)
              {
              if (!this->HasJacobianChangedSign(linearVolumeCell,quadraticVolumeCell))
                {
                break;
                }
              anySignChange = true;
              vtkWarningMacro(<<"Warning: projection causes element "<<volumeCellId<<" to have a negative Jacobian somewhere. Relaxing projection for this element.");
              double relaxation = (double)(s+1)/(double)numberOfRelaxationSteps;
              for (j=0; j<3; j++)
                {
                facePoint[j] = (1.0 - relaxation) * projectedFacePoint0123[j] + relaxation * (0.25 * (point0[j] + point1[j] + point2[j] + point3[j]));
                }
              outputPoints->SetPoint(facePointId0123,facePoint);
              quadraticVolumeCell = output->GetCell(volumeCellId);
              }
            volumeCellIds->Delete();
            }
          }
        }
      }
    }

  if (this->TestFinalJacobians)
    {
    for (i=0; i<numberOfCells; i++)
      {
      vtkCell* linearVolumeCell = input->GetCell(i);
      if (linearVolumeCell->GetCellDimension() != 3)
        {
        continue;
        }
      vtkIdType outputCellId = inputToOutputCellIds->GetId(i);
      if (outputCellId == -1)
        {
        continue;
        }
      vtkCell* quadraticVolumeCell = output->GetCell(outputCellId);
  
      if (this->HasJacobianChangedSign(linearVolumeCell,quadraticVolumeCell))
        {
        vtkErrorMacro("Error: negative Jacobian detected in cell "<<outputCellId<<" even after relaxation. Output quadratic mesh will have negative Jacobians.");
        }
      }
    }

  surfaceEdgeTable->Delete();
  surfaceFaceTable->Delete();

  outputPoints->Delete();
  edgeTable->Delete();
  faceTable->Delete();

  triangleIds->Delete();
  tetraIds->Delete();
  wedgeIds->Delete();
  hexahedraIds->Delete();
  quadIds->Delete();
  facePointIds->Delete();
  cellNeighbors->Delete();

  cell->Delete();
  if (locator)
    {
    locator->Delete();
    locator = NULL;
    }
  cellEntityIdsArray->Delete();

  inputToOutputCellIds->Delete();

  output->Squeeze();

  return 1;
}

double vtkvmtkLinearToQuadraticMeshFilter::ComputeJacobian(vtkCell* cell, double pcoords[3])
{
  double jacobian = 0.0;

  int numberOfCellPoints = cell->GetNumberOfPoints();
  double* derivs = new double[3*numberOfCellPoints];
  
  vtkvmtkFEShapeFunctions::GetInterpolationDerivs(cell,pcoords,derivs);
  
  int i, j;
  
  double jacobianMatrix[3][3];
  for (i=0; i<3; i++)
    {
    jacobianMatrix[0][i] = jacobianMatrix[1][i] = jacobianMatrix[2][i] = 0.0;
    }
  
  double x[3];
  for (j=0; j<numberOfCellPoints; j++)
    {
    cell->GetPoints()->GetPoint(j,x);
    for (i=0; i<3; i++)
      {
      jacobianMatrix[0][i] += x[i] * derivs[j];
      jacobianMatrix[1][i] += x[i] * derivs[numberOfCellPoints+j];
      jacobianMatrix[2][i] += x[i] * derivs[2*numberOfCellPoints+j];
      }
    }
  delete[] derivs;

  jacobian = vtkMath::Determinant3x3(jacobianMatrix);

  return jacobian;
}

bool vtkvmtkLinearToQuadraticMeshFilter::HasJacobianChangedSign(vtkCell* linearVolumeCell, vtkCell* quadraticVolumeCell)
{
  vtkvmtkGaussQuadrature* gaussQuadrature = vtkvmtkGaussQuadrature::New();
  gaussQuadrature->SetOrder(this->QuadratureOrder);
  gaussQuadrature->Initialize(quadraticVolumeCell->GetCellType());
  bool signChanged = false;
  int numberOfQuadraturePoints = gaussQuadrature->GetNumberOfQuadraturePoints();
  double quadraturePCoords[3];
  int q;
  for (q=0; q<numberOfQuadraturePoints; q++)
    {
    gaussQuadrature->GetQuadraturePoint(q,quadraturePCoords);
    double linearJacobian = this->ComputeJacobian(linearVolumeCell,quadraturePCoords);
    double quadraticJacobian = this->ComputeJacobian(quadraticVolumeCell,quadraturePCoords);
    if (linearJacobian*quadraticJacobian < 0.0)
      {
      signChanged = true;
      break;
      }
    }
  gaussQuadrature->Delete();
  if (signChanged)
    {
    return signChanged;
    }

  double* parametricCoords = quadraticVolumeCell->GetParametricCoords();
  int numberOfCellPoints = quadraticVolumeCell->GetNumberOfPoints();
  for (q=0; q<numberOfCellPoints; q++)
    {
    quadraturePCoords[0] = parametricCoords[q*numberOfCellPoints + 0];
    quadraturePCoords[1] = parametricCoords[q*numberOfCellPoints + 1];
    quadraturePCoords[2] = parametricCoords[q*numberOfCellPoints + 2];
    double linearJacobian = this->ComputeJacobian(linearVolumeCell,quadraturePCoords);
    double quadraticJacobian = this->ComputeJacobian(quadraticVolumeCell,quadraturePCoords);
    if (linearJacobian*quadraticJacobian < this->NegativeJacobianTolerance)
      {
      signChanged = true;
      break;
      }
    }

  return signChanged;
}

void vtkvmtkLinearToQuadraticMeshFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/interact.c<|end_filename|>
/*****************************************************************************/
/*      Routines to interact with the user                                   */
/*****************************************************************************/

/* print out all the improvement settings */
void printimproveoptionsstream(FILE *o, struct improvebehavior *b)
{
    fprintf(o,"** Mesh Improvement Options **\n");
    
    fprintf(o,"Output file prefix: %s\n", b->fileprefix);
    
    fprintf(o,"    Quality measure:          "); fprintf(o,"%d\n", b->qualmeasure);
    fprintf(o,"    Sine warp factor:         "); fprintf(o,"%g\n", b->sinewarpfactor);
    fprintf(o,"    Quadric surface error:    "); b->usequadrics ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Quadric offset:           "); fprintf(o,"%g\n", b->quadricoffset);
    fprintf(o,"    Quadric scale:            "); fprintf(o,"%g\n", b->quadricscale);
    
    fprintf(o,"Smoothing options:\n");
    fprintf(o,"    Optimization-based:       "); b->nonsmooth ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Facet vertex smoothing:   "); b->facetsmooth ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Segment vertex smoothing: "); b->segmentsmooth ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    
    fprintf(o,"Topological improvement options:\n");
    fprintf(o,"    Edge removal:             "); b->edgeremoval ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Edge contraction:         "); b->edgecontraction ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Boundary edge removal:    "); b->boundedgeremoval ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Single-face removal:      "); b->singlefaceremoval ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Multi-face removal:       "); b->multifaceremoval ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    2-2 flips:                "); b->flip22 ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Star internal flips:      "); b->jflips ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    
    fprintf(o,"Vertex insertion options:\n");
    fprintf(o,"    Vertex insertion:         "); b->enableinsert ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Insert in worst percent:  "); fprintf(o,"%g\n", b->insertthreshold);
    fprintf(o,"    Body vertex insertion:    "); b->insertbody ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Facet vertex insertion:   "); b->insertfacet ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Segment vertex insertion: "); b->insertsegment ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    
    fprintf(o,"Element sizing options:\n");
    fprintf(o,"    Size control:             "); b->sizing ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Size control pass:        "); b->sizingpass ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Target edge length:       "); fprintf(o,"%g\n", b->targetedgelength);
    fprintf(o,"    Longer edge factor:       "); fprintf(o,"%g\n", b->longerfactor);
    fprintf(o,"    Shorter edge factor:      "); fprintf(o,"%g\n", b->shorterfactor);
    
    fprintf(o,"Anisotropic meshing options:\n");
    fprintf(o,"    Anisotropic meshing:      "); b->anisotropic ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Tensor scaling field:     "); fprintf(o,"%d\n", b->tensor);
    fprintf(o,"    Second tensor:            "); fprintf(o,"%d\n", b->tensorb);
    fprintf(o,"    Amount:                   "); fprintf(o,"%g\n", b->tensorblend);
    
    fprintf(o,"Dynamic improvement options:\n");
    fprintf(o,"    Minimum quality:          "); fprintf(o,"%g\n", pq(b->dynminqual));
    fprintf(o,"    Improve to quality:       "); fprintf(o,"%g\n", pq(b->dynimproveto));
    fprintf(o,"    Deformation type:         "); fprintf(o,"%d\n", b->deformtype);
    fprintf(o,"    Do dynamic improvement:   "); fprintf(o,"%d\n", b->dynimprove);
    
    fprintf(o,"Thresholds:\n");
    fprintf(o,"    Minimum mean improvement: "); fprintf(o,"%g\n", b->minstepimprovement);
    fprintf(o,"    Don't insert above qual:  "); fprintf(o,"%g\n", b->maxinsertquality[b->qualmeasure]);
    
    fprintf(o,"Termination options:\n");
    fprintf(o,"    Stop if smallest angle >: "); fprintf(o,"%g\n", b->goalanglemin);
    fprintf(o,"    Stop if largest angle <:  "); fprintf(o,"%g\n", b->goalanglemax);
    
    fprintf(o,"Quality file output options:\n");
    fprintf(o,"    Output .minsine file:     "); b->minsineout ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Output .minang file:     "); b->minangout ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Output .maxang file:     "); b->maxangout ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Output .vlrms file:     "); b->vlrmsout ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"    Output .nrr file:     "); b->nrrout ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    
    fprintf(o,"Animation file output: "); b->animate ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    fprintf(o,"Timeseries .stats only: "); b->timeseries ? fprintf(o,"enabled\n") : fprintf(o,"disabled\n");
    
    fprintf(o,"Verbosity:             "); fprintf(o,"%d\n", b->verbosity);
    
    fprintf(o,"\n");
}

void printimproveoptions(struct improvebehavior *b)
{
    printimproveoptionsstream(stdout, b);
}

void parseimproveconfig(char *filename, struct improvebehavior *b)
{
    char word[100];      /* variable name from config file */
    int value=0;         /* variable value from config file */
    starreal fvalue=0.0; /* variable for floats in config file */
    char str[100];
    char fstr[100];
    
    /* temp stuff for line reading */
    int nbytes = 1000;
    char line[1000];
    int numassigned;
    
    FILE *in = fopen(filename, "r");
    assert(in != NULL);
    
    if (improvebehave.verbosity > 4)
    {
        printf("parsing settings file %s\n", filename);
    }
    
    /* read every line of the file */
    while (fgets(line, nbytes, in) != NULL)
    {
        /* attempt to fetch a variable name and value from the config file */
        numassigned = sscanf(line, "%s %d %s %s", word, &value, fstr, str);
        fvalue = atof(fstr);
        
        /* check if this is a comment */
        if (word[0] == '#' || word[0] == '\n' || numassigned == 0) continue;
        
        if (improvebehave.verbosity > 5)
        {
            printf("just read variable %s with value int %d float %g string `%s'\n", word, value, fvalue, str);
        }
        
        /* assign behavior variables based on input */
        if (strcmp(word,"qualmeasure") == 0) b->qualmeasure = value;
        if (strcmp(word,"sinewarpfactor") == 0) b->sinewarpfactor = fvalue;
        if (strcmp(word,"usequadrics") == 0) b->usequadrics = value;
        /* alias old fixed smooth option to usequadrics */
        if (strcmp(word,"usequadrics") == 0) b->fixedsmooth = value;
        if (strcmp(word,"quadricoffset") == 0) b->quadricoffset = fvalue;
        if (strcmp(word,"quadricscale") == 0) b->quadricscale = fvalue;
        
        if (strcmp(word,"nonsmooth") == 0) b->nonsmooth = value;
        if (strcmp(word,"facetsmooth") == 0) b->facetsmooth = value;
        if (strcmp(word,"segmentsmooth") == 0) b->segmentsmooth = value;
        
        if (strcmp(word,"edgeremoval") == 0) b->edgeremoval = value;
        if (strcmp(word,"edgecontraction") == 0) b->edgecontraction = value;
        if (strcmp(word,"boundedgeremoval") == 0) b->boundedgeremoval = value;
        if (strcmp(word,"singlefaceremoval") == 0) b->singlefaceremoval = value;
        if (strcmp(word,"multifaceremoval") == 0) b->multifaceremoval = value;
        if (strcmp(word,"flip22") == 0) b->flip22 = value;
        if (strcmp(word,"jflips") == 0) b->jflips = value;
        
        if (strcmp(word,"insertthreshold") == 0) b->insertthreshold = fvalue;
        if (strcmp(word,"enableinsert") == 0) b->enableinsert = value;
        if (strcmp(word,"insertfacet") == 0) b->insertfacet = value;
        if (strcmp(word,"insertbody") == 0) b->insertbody = value;
        if (strcmp(word,"insertsegment") == 0) b->insertsegment = value;
        if (strcmp(word,"cavityconsiderdeleted") == 0) b->cavityconsiderdeleted = value;
        if (strcmp(word,"cavdepthlimit") == 0) b->cavdepthlimit = value;
        
        if (strcmp(word,"minstepimprovement") == 0) b->minstepimprovement = fvalue;
        if (strcmp(word,"maxinsertquality") == 0) b->maxinsertquality[b->qualmeasure] = fvalue;
        
        if (strcmp(word,"anisotropic") == 0) b->anisotropic = value;
        if (strcmp(word,"tensor") == 0) b->tensor = value;
        if (strcmp(word,"tensorb") == 0) b->tensorb = value;
        if (strcmp(word,"tensorblend") == 0) b->tensorblend = fvalue;
        
        if (strcmp(word,"sizing") == 0) b->sizing = value;
        if (strcmp(word,"sizingpass") == 0) b->sizingpass = value;
        if (strcmp(word,"targetedgelength") == 0) b->targetedgelength = fvalue;
        if (strcmp(word,"longerfactor") == 0) b->longerfactor = fvalue;
        if (strcmp(word,"shorterfactor") == 0) b->shorterfactor = fvalue;
        
        if (strcmp(word,"minsineout") == 0) b->minsineout = value;
        if (strcmp(word,"minangout") == 0) b->minangout = value;
        if (strcmp(word,"maxangout") == 0) b->maxangout = value;
        if (strcmp(word,"vlrmsout") == 0) b->vlrmsout = value;
        if (strcmp(word,"nrrout") == 0) b->nrrout = value;
        
        if (strcmp(word,"fileprefix") == 0) strcpy(b->fileprefix, str);
        
        if (strcmp(word,"animate") == 0) b->animate = value;
        if (strcmp(word,"timeseries") == 0) b->timeseries = value;
        if (strcmp(word,"usecolor") == 0) b->usecolor = value;
        
        if (strcmp(word,"verbosity") == 0) b->verbosity = value;
        
        if (strcmp(word,"goalanglemin") == 0) b->goalanglemin = fvalue;
        if (strcmp(word,"goalanglemax") == 0) b->goalanglemax = fvalue;
        
        if (strcmp(word,"dynminqual") == 0) b->dynminqual = fvalue;
        if (strcmp(word,"dynimproveto") == 0) b->dynimproveto = fvalue;
        if (strcmp(word,"deformtype") == 0) b->deformtype = value;
        if (strcmp(word,"dynimprove") == 0) b->dynimprove = value;
        
        if (strcmp(word,"outputandquit") == 0) b->outputandquit = value;
    }
}

void parseimprovecommandline(int argc, char **argv, struct improvebehavior *b)
{
    int i;
    
    /* set default values for all options */
    b->qualmeasure = QUALMINSINE;
    /*
    b->qualmeasure = QUALWARPEDMINSINE;
    b->qualmeasure = QUALRADIUSRATIO;
    b->qualmeasure = QUALVLRMS3RATIO;
    */
    b->sinewarpfactor = 0.75;
    b->usequadrics = 1;
    b->quadricoffset = 0.8;
    b->quadricscale = 300.0;
    
    b->nonsmooth = 1;
    b->facetsmooth = 1;
    b->segmentsmooth = 1;
    b->fixedsmooth = 0;
    
    b->edgeremoval = 1;
    b->boundedgeremoval = 0;
    b->singlefaceremoval = 1;
    b->multifaceremoval = 1;
    b->flip22 = 1;
    b->jflips = 1;
    
    b->insertthreshold = 0.035;
    b->enableinsert = 1;
    b->insertfacet = 1;
    b->insertbody = 1;
    b->insertsegment = 1;
    b->cavityconsiderdeleted = 0;
    b->cavdepthlimit = 6;
    
    b->edgecontraction = 1;
    
    b->minstepimprovement = 1.0e-4;
    b->mininsertionimprovement = 1.0e-3;
    b->maxinsertquality[0] = SINE40;
    b->maxinsertquality[1] = 0.7;
    b->maxinsertquality[2] = 0.7; 
    b->maxinsertquality[5] = SINE40;
    
    b->anisotropic = 0;
    b->tensor = 0;
    b->tensorb = 0;
    b->tensorblend = 1.0;
    
    b->sizing = 0;
    b->sizingpass = 0;
    b->targetedgelength = 0.0;
    b->longerfactor = 2.0;
    b->shorterfactor = 0.5;
    
    b->dynminqual = SINE20;
    b->dynimproveto = SINE25;
    b->deformtype = TWIST;
    b->dynimprove = 0;
    
    b->verbosity = 1;
    b->usecolor = 0;
    
    b->outputandquit = 0;
    
    b->minsineout = 1;
    b->minangout = 0;
    b->maxangout = 0;
    b->vlrmsout = 0;
    b->nrrout = 0;
    
    strcpy(b->fileprefix, "");
    /*
    strcpy(b->fileprefix, "default");
    */
    
    b->animate = 0;
    b->timeseries = 0;
    
    b->goalanglemin = 90.0;
    b->goalanglemax = 90.0;
    
    if (improvebehave.verbosity > 5)
    {
        printf("finding config file name in args\n");
    }
    
    /* loop through each argument */
    for (i=0; i<argc; i++)
    {
        /* check if this is L */
        if (strcmp(argv[i], "-L") == 0)
        {
            /* set verbosity */
            improvebehave.verbosity = atoi(argv[i+1]);
        }
        
        /* check if this is F */
        if (strcmp(argv[i], "-F") == 0)
        {
            /* set to just output and quit */
            improvebehave.outputandquit = 1;
        }
        
        /* check if this is s */
        if (strcmp(argv[i], "-s") == 0)
        {
            /* parse and set the options from this file */
            parseimproveconfig(argv[i+1], b);
        }
    }
}











<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/smoothing.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*  smoothing functions                                                      */
/*                                                                           */
/*****************************************************************************/

/* given two values a and b and their gradients, compute the 
   gradient of their product grad(a*b) */
void gradproduct(starreal a, 
                 starreal b, 
                 starreal grada[3],
                 starreal gradb[3],
                 starreal prod[3])
{
    prod[0] = grada[0] * b + gradb[0] * a;
    prod[1] = grada[1] * b + gradb[1] * a;
    prod[2] = grada[2] * b + gradb[2] * a;
}

/* given two values top and bottom and their gradients, compute the 
   gradient of their quotient grad(top / bottom) */
void gradquotient(starreal top, 
                  starreal bot, 
                  starreal gradtop[3],
                  starreal gradbot[3],
                  starreal quot[3])
{
    starreal denom = bot * bot;
    quot[0] = (bot * gradtop[0] - top * gradbot[0]) / denom;
    quot[1] = (bot * gradtop[1] - top * gradbot[1]) / denom;
    quot[2] = (bot * gradtop[2] - top * gradbot[2]) / denom;
}

/* get the information about this tet needed for non-smooth
   optimization of the current quality measure */
void getoptinfo(struct tetcomplex *mesh,
                 struct opttet *opttet,
                 int vtxkind,
                 starreal vtxvec[3])
{
    starreal point[4][3];       /* the vertices of the tet */
    starreal edgelength[3][4];  /* the lengths of each of the edges of the tet */
    starreal edgegrad[3][4][3]; /* the gradient of each edge length wrt vtx1 */
    starreal facenormal[4][3];  /* the normals of each face of the tet */
    starreal facearea[4];       /* areas of the faces of the tet */
    starreal facegrad[4][3];    /* the gradient of each of the face areas wrt vtx1 */
    starreal volume;            /* volume of tetrahedron */
    starreal volumegrad[3] = {0.0, 0.0, 0.0};     /* the gradient of the volume of the tet wrt vtx1 */
    int i, j, k, l;           /* loop indices */
    int edgecount=0;          /* keep track of current edge */
    starreal ejk[3];            /* vector representing edge from j to k */
    starreal ejl[3];            /* vector representing edge from j to l */
    starreal t[3];
    starreal u[3];
    starreal v[3];
    starreal e1[3] = {0.0, 0.0, 0.0};
    starreal e2[3] = {0.0, 0.0, 0.0};
    
    /* temporary variables */
    starreal diff[3];
    starreal term1[3];
    starreal term2[3];
    starreal factor;
    starreal c;
    starreal top, bot;
    starreal gradtop[3];
    starreal gradbot[3];
    starreal gradquot[3];
    
    /* radius ratio vars */
    starreal Z;
    starreal twooverZ;
    starreal gradZtfac, gradZufac, gradZvfac;
    starreal gradZt[3];
    starreal gradZu[3];
    starreal gradZv[3];
    starreal gradZ[3];
    starreal faceareasum;
    starreal rootZareasum;
    starreal facegradsum[3];
    starreal vdott;
    starreal tdotu;
    starreal udotv;
    starreal tlen2;
    starreal ulen2;
    starreal vlen2;
    starreal uminusv[3];
    starreal vminust[3];
    starreal tminusu[3];
    starreal umvlen2;
    starreal vmtlen2;
    starreal tmulen2;
    starreal normfac = sqrt(3.0) * 6.0;
    starreal rnrrgradterm1[3], rnrrgradterm2[3];
    starreal E[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
    
    /* V / lrms^3 ratio vars */
    starreal edgelengthsum = 0.0;
    starreal lrms;
    starreal gradlrms[3];
    starreal vlrmsterm1[3];
    starreal vlrmsterm2[3];

    if (improvebehave.verbosity > 5)
    {
        printf("computing opt info for the following tet:\n");
        printtetverts(mesh, opttet->verts);
        printf("\n");
    }

    /* get tet vertices */
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, opttet->verts[0]))->coord, point[0]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, opttet->verts[1]))->coord, point[1]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, opttet->verts[2]))->coord, point[2]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, opttet->verts[3]))->coord, point[3]);
    
    /* if anisotropic meshing is enabled, warp the points according the
       deformation tensor at their barycenter */
    if (improvebehave.anisotropic)
    {
        /* fetch the deformation tensor at the barycenter of this tet */
        tettensor(mesh, opttet->verts[0], opttet->verts[1], opttet->verts[2], opttet->verts[3], E);
        
        /* transform each vertex */
        for (i=0; i<4; i++)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("in getoptinfo transforming point (%g %g %g) ->", point[i][0], point[i][1], point[i][2]);
            }
            
            tensortransform(point[i], point[i], E);
            
            if (improvebehave.verbosity > 5)
            {
                printf(" (%g %g %g)\n", point[i][0], point[i][1], point[i][2]);
            }
        }
    }
    
    /* set some vectors */
    vsub(point[1], point[0], t);
    vsub(point[2], point[0], v);
    vsub(point[3], point[0], u);
    
    /* calculate the volume*6 of the tetrahedron using orientation */
    volume = (starreal) orient3d(&behave, point[0], point[1], point[2], point[3]) / 6.0;
    opttet->volume = volume;
    
    if (improvebehave.verbosity > 5)
    {
        printf("tetvolume = %g\n", volume);
    }
    
    /* for each vertex/face of the tetrahedron */
    for (i = 0; i < 4; i++) {
        j = (i + 1) & 3;
        if ((i & 1) == 0) {
            k = (i + 3) & 3;
            l = (i + 2) & 3;
        } else {
            k = (i + 2) & 3;
            l = (i + 3) & 3;
        }
        
        /* compute the normal for each face */
        /* for each vertex i in the loop, the ith face is the face
           opposite i, so that face's normal is found by taking the
           cross product of two edges of the opposite face */
        /* TODO implement this cross product with Orient2D calls? */
        
        /* one edge on opposite face */
        vsub(point[k], point[j], ejk);
        
        /* another edge originating from the same vertex */
        vsub(point[l], point[j], ejl);
        
        /* compute a normal vector to this face */
        cross(ejk, ejl, facenormal[i]);
        
        /* if i=0, this is also the gradient of the volume * 6
           with respect to vertex 0 */
        if (i==0)
        {
            opttet->volumegrad[0] = volumegrad[0] = -facenormal[i][0] / 6.0;
            opttet->volumegrad[1] = volumegrad[1] = -facenormal[i][1] / 6.0;
            opttet->volumegrad[2] = volumegrad[2] = -facenormal[i][2] / 6.0;
        }
        
        /* compute (2 *area)^2 for this face */
        facearea[i] = facenormal[i][0] * facenormal[i][0] +
            facenormal[i][1] * facenormal[i][1] +
            facenormal[i][2] * facenormal[i][2];
        /* now get the real area */
        opttet->facearea[i] = facearea[i] = sqrt(facearea[i]) / 2.0;
            
        /* compute the gradient of the area for this face */
        if (i==0)
        {
            /* this face doesn't include vtx1, gradient is zero */
            opttet->facegrad[i][0] = facegrad[i][0] = 0.0;
            opttet->facegrad[i][1] = facegrad[i][1] = 0.0;
            opttet->facegrad[i][2] = facegrad[i][2] = 0.0;
        }
        else
        {
            if (improvebehave.verbosity > 4)
            {
                if (facearea[i] <= 0)
                {
                    printf("found non-positive face area %g in tet (%d %d %d %d)\n", facearea[i], (int) opttet->verts[0], (int) opttet->verts[1], (int) opttet->verts[2], (int) opttet->verts[3]);
                    printf("tetexists = %d", tetexists(mesh, opttet->verts[0], opttet->verts[1], opttet->verts[2], opttet->verts[3]));
                    printtetverts(mesh, opttet->verts);
                    printf("\n\n\n");
                }
            }
            assert(facearea[i] > 0);
            /* gradient scaled by the face's area */
            factor = 1.0 / (4.0 * facearea[i]);
            
            /* handle each face separately */
            switch(i)
            {
                /* compute the area of face 1 using u and v */
                case 1:
                    vcopy(u, e1);
                    vcopy(v, e2);
                    break;
                case 2:
                    vcopy(t, e1);
                    vcopy(u, e2);
                    break;
                case 3:
                    vcopy(v, e1);
                    vcopy(t, e2);
                    break;
            }
            
            /* find the vector from elk to elj */
            vsub(e1, e2, diff);
            
            /* compute first term of gradient */
            c = dot(e2,diff);
            term1[0] = c * e1[0];
            term1[1] = c * e1[1];
            term1[2] = c * e1[2];
            
            /* compute the second term */
            c = dot(e1,diff);
            term2[0] = c * e2[0];
            term2[1] = c * e2[1];
            term2[2] = c * e2[2];
            
            /* now, combine the terms, scaled with the 1/4A */
            opttet->facegrad[i][0] = facegrad[i][0] = factor * (term1[0] - term2[0]);
            opttet->facegrad[i][1] = facegrad[i][1] = factor * (term1[1] - term2[1]);
            opttet->facegrad[i][2] = facegrad[i][2] = factor * (term1[2] - term2[2]);
        }
        
            
        /* compute edge lengths for quality measures that need them */
        if (improvebehave.qualmeasure == QUALMINSINE ||
            improvebehave.qualmeasure == QUALWARPEDMINSINE ||
            improvebehave.qualmeasure == QUALVLRMS3RATIO)
        {
            for (j = i + 1; j < 4; j++) {
            
                /* e1 is edge from point i to point j */
                vsub(point[j], point[i], e1);
                opttet->edgelength[i][j] = edgelength[i][j] = vlength(e1);
            
                /* also compute the gradient of the length of this edge */
            
                /* if vtx1 isn't one of the edge's endpoints, the gradent is zero */
                if (i != 0)
                {
                    opttet->edgegrad[i][j][0] = edgegrad[i][j][0] = 0.0;
                    opttet->edgegrad[i][j][1] = edgegrad[i][j][1] = 0.0;
                    opttet->edgegrad[i][j][2] = edgegrad[i][j][2] = 0.0;
                }
                /* otherwise, it's in the negative direction of this edge,
                   and scaled by edge length */
                else
                { 
                    factor = -1.0 / edgelength[i][j];
                    vscale(factor, e1, edgegrad[i][j]);
                    vcopy(edgegrad[i][j], opttet->edgegrad[i][j]);
                }
            }
        }
    }
    
    /* if the quality measure is minimum sine */
    if ((improvebehave.qualmeasure == QUALMINSINE) ||
        (improvebehave.qualmeasure == QUALWARPEDMINSINE))
    {
        /* for each edge in the tetrahedron */
        for (i = 0; i < 3; i++) {
            for (j = i + 1; j < 4; j++) {
                k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
                l = 6 - i - j - k;
            
                /* compute the sine of this dihedral angle */
                opttet->sine[edgecount] = (3 * volume * edgelength[i][j]) / (2 * facearea[k] * facearea[l]);
                
                /* if we are warping the minimum sine */
                if (improvebehave.qualmeasure == QUALWARPEDMINSINE)
                {
                    /* and this is an obtuse angle */
                    if (dot(facenormal[k],facenormal[l]) > 0)
                    {
                        if (improvebehave.verbosity > 5)
                        {
                            printf("in grad compute, scaling down obtuse sin from %g to %g\n", opttet->sine[edgecount], opttet->sine[edgecount] * improvebehave.sinewarpfactor);
                        }
                        
                        /* scale the sin down by WARPFACTOR */
                        opttet->sine[edgecount] *= improvebehave.sinewarpfactor;
                    }
                }
            
                /* compute the gradient of the sine
               
                   we need the gradient of this expression:
               
                   3 * V * lij
                   ------------
                   2 * Ak * Al
               
                   so, find the gradient of the top product, the bottom product, then the quotient
                */
                top = volume * edgelength[i][j];
                bot = facearea[k] * facearea[l];
            
                /* find gradient of top */
                gradproduct(volume, edgelength[i][j], volumegrad, edgegrad[i][j], gradtop);
            
                /* find gradient of bottom */
                gradproduct(facearea[k], facearea[l], facegrad[k], facegrad[l], gradbot);
            
                /* now, find the gradient of the quotient */
                gradquotient(top, bot, gradtop, gradbot, gradquot);
            
                /* now scale with constant factor */
                c = 3.0 / 2.0;
                opttet->sinegrad[edgecount][0] = c * gradquot[0];
                opttet->sinegrad[edgecount][1] = c * gradquot[1];
                opttet->sinegrad[edgecount][2] = c * gradquot[2];
            
                /* if this is a facet vertex, project gradient onto facet */
                /*
                if (vtxkind == FACETVERTEX || vtxkind == FIXEDVERTEX)
                */
                if (vtxkind == FACETVERTEX)
                {
                    vprojecttoplane(opttet->sinegrad[edgecount], vtxvec, opttet->sinegrad[edgecount]);
                }
            
                /* if this is a segment vertex, project gradient onto segment */
                if (vtxkind == SEGMENTVERTEX)
                {
                    if (improvebehave.verbosity > 5)
                    {
                        printf("when trying to project to segment, vtxvec is %g %g %g, length %g\n", vtxvec[0], vtxvec[1], vtxvec[2], vlength(vtxvec));
                        printf("sine gradient before projection is %g %g %g\n", opttet->sinegrad[edgecount][0],
                                                                            opttet->sinegrad[edgecount][1],
                                                                            opttet->sinegrad[edgecount][2]);
                    }
                    vproject(opttet->sinegrad[edgecount], vtxvec, opttet->sinegrad[edgecount]);
                
                    if (improvebehave.verbosity > 5)
                    {
                        printf("sine gradient after  projection is %g %g %g\n", opttet->sinegrad[edgecount][0],
                                        opttet->sinegrad[edgecount][1],
                                        opttet->sinegrad[edgecount][2]);
                    }
                }
            
                edgecount++;
            }
        }
    }
    
    /* compute stuff for radius ratio */
    if (improvebehave.qualmeasure == QUALRADIUSRATIO)
    {
        /* compute intermediate quantity Z */
        Z = getZ(point[0], point[1], point[2], point[3]);
        
        if (improvebehave.verbosity > 5)
        {
            printf("Z is %g\n", Z);
        }
        
        twooverZ = 2.0 / Z;
        
        /* some dot products */
        vdott = dot(v, t);
        tdotu = dot(t, u);
        udotv = dot(u, v);
        
        if (improvebehave.verbosity > 5)
        {
            printf("vdott = %g\n", vdott);
            printf("tdotu = %g\n", tdotu);
            printf("udotv = %g\n", udotv);
        }
        
        /* some vector lengths */
        vsub(u, v, uminusv);
        vsub(v, t, vminust);
        vsub(t, u, tminusu);
        tlen2 = (t[0] * t[0]) + (t[1] * t[1]) + (t[2] * t[2]);
        ulen2 = (u[0] * u[0]) + (u[1] * u[1]) + (u[2] * u[2]);
        vlen2 = (v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2]);
        umvlen2 = (uminusv[0] * uminusv[0]) + (uminusv[1] * uminusv[1]) + (uminusv[2] * uminusv[2]);
        vmtlen2 = (vminust[0] * vminust[0]) + (vminust[1] * vminust[1]) + (vminust[2] * vminust[2]);
        tmulen2 = (tminusu[0] * tminusu[0]) + (tminusu[1] * tminusu[1]) + (tminusu[2] * tminusu[2]);
        
        if (improvebehave.verbosity > 5)
        {
            printf("tlen2 = %g\n", tlen2);
            printf("ulen2 = %g\n", ulen2);
            printf("vlen2 = %g\n", vlen2);
            printf("umvlen2 = %g\n", umvlen2);
            printf("vmtlen2 = %g\n", vmtlen2);
            printf("tmulen2 = %g\n", tmulen2);
        }
        
        /* compute Z's gradient */
        gradZtfac = twooverZ * 
                 (
                    (ulen2 * vdott - vlen2 * tdotu) * (ulen2 - vlen2) - 
                    (ulen2 * vlen2 + tlen2 * udotv) * (umvlen2)
                 );
        gradZufac = twooverZ * 
                 (
                    (vlen2 * tdotu - tlen2 * udotv) * (vlen2 - tlen2) - 
                    (vlen2 * tlen2 + ulen2 * vdott) * (vmtlen2)
                 );
        gradZvfac = twooverZ * 
                 (
                    (tlen2 * udotv - ulen2 * vdott) * (tlen2 - ulen2) - 
                    (tlen2 * ulen2 + vlen2 * tdotu) * (tmulen2)
                 );
        
        if (improvebehave.verbosity > 5)
        {
            printf("tfac is %g\n", gradZtfac);
            printf("ufac is %g\n", gradZufac);
            printf("vfac is %g\n", gradZvfac);
        }
        
        /* compute t, u, v components of gradient */
        vscale(gradZtfac, t, gradZt);
        vscale(gradZufac, u, gradZu);
        vscale(gradZvfac, v, gradZv);
        
        /* add the components together to form grad(Z) */
        vadd(gradZt, gradZu, gradZ);
        vadd(gradZv, gradZ, gradZ);
        
        if (improvebehave.verbosity > 5)
        {
            printf("gradZ is (%g, %g, %g)\n", gradZ[0], gradZ[1], gradZ[2]);
        }
        
        /* compute sqrt (Z * (sum of face areas)) */
        faceareasum = opttet->facearea[0] +
                      opttet->facearea[1] +
                      opttet->facearea[2] +
                      opttet->facearea[3];
        rootZareasum = sqrt(Z * faceareasum);
        
        /* set the actual root normalized radius ratio */
        opttet->rnrr = (normfac * volume) / rootZareasum;
        
        if (improvebehave.verbosity > 5)
        {
            printf("rnrr = %g\n", opttet->rnrr);
        }
        
        assert(opttet->rnrr > 0.0);
        
        if (improvebehave.verbosity > 5)
        {
            starreal thisqual = tetquality(mesh, opttet->verts[0], opttet->verts[1], opttet->verts[2], opttet->verts[3], improvebehave.qualmeasure);
            printf("rnrr = %g, thisqual = %g, diff = %g\n", opttet->rnrr, thisqual, opttet->rnrr - thisqual);
            assert(opttet->rnrr - thisqual < 1e-13);
        }
        
        /* sum of face gradients */
        vadd(facegrad[0], facegrad[1], facegradsum);
        vadd(facegrad[2], facegradsum, facegradsum);
        vadd(facegrad[3], facegradsum, facegradsum);
        
        /* compute the first term */
        vscale((1.0 / rootZareasum), volumegrad, rnrrgradterm1);
        
        if (improvebehave.verbosity > 5)
        {
            printf("firstterm is (%g, %g, %g)\n", rnrrgradterm1[0], rnrrgradterm1[1], rnrrgradterm1[2]);
        }
        
        /* compute the second term */
        vscale(Z, facegradsum, facegradsum);
        vscale(faceareasum, gradZ, gradZ);
        vadd(facegradsum, gradZ, rnrrgradterm2);
        vscale(volume / (2 * (rootZareasum * rootZareasum * rootZareasum)), rnrrgradterm2, rnrrgradterm2);
        
        if (improvebehave.verbosity > 5)
        {
            printf("secondterm is (%g, %g, %g)\n", rnrrgradterm2[0], rnrrgradterm2[1], rnrrgradterm2[2]);
        }
        
        /* finally, compute the gradient of the radius ratio */
        vsub(rnrrgradterm1, rnrrgradterm2, opttet->rnrrgrad);
        vscale(normfac, opttet->rnrrgrad, opttet->rnrrgrad);
        
        /* if this is a facet vertex, project gradient onto facet */
        /*if (vtxkind == FACETVERTEX || vtxkind == FIXEDVERTEX)*/
        if (vtxkind == FACETVERTEX)
        {
            vprojecttoplane(opttet->rnrrgrad, vtxvec, opttet->rnrrgrad);
        }
    
        /* if this is a segment vertex, project gradient onto segment */
        if (vtxkind == SEGMENTVERTEX)
        {
            vproject(opttet->rnrrgrad, vtxvec, opttet->rnrrgrad);
        }
        
        if (improvebehave.verbosity > 5 || opttet->rnrr < 0.0)
        {
            printf("computing opt info for the following tet, negative qual = %g:\n", opttet->rnrr);
            printtetverts(mesh, opttet->verts);
            printf("\n");
            printf("rnrrgrad is (%g %g %g)\n", opttet->rnrrgrad[0], opttet->rnrrgrad[1], opttet->rnrrgrad[2]);
            starexit(1);
        }
    }
    
    /* if the quality measure is volume to edge length ratio */
    if (improvebehave.qualmeasure == QUALVLRMS3RATIO)
    {
        /* for each edge in the tetrahedron */
        for (i = 0; i < 3; i++) 
        {
            for (j = i + 1; j < 4; j++) 
            {
                k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
                l = 6 - i - j - k;
                
                /* accumulate edge length sum */
                edgelengthsum += edgelength[i][j] * edgelength[i][j];
            }
        }
        
        /* compute the root mean square */
        lrms = sqrt((1.0 / 6.0) * edgelengthsum);
        
        if (improvebehave.verbosity > 5)
        {
            printf("edgelengthsum = %g, lrms = %g\n", edgelengthsum, lrms);
        }
        
        normfac = 6.0 * sqrt(2.0);
        
        /* compute the raw ratio */
        opttet->vlrms3r = (normfac * volume) / (lrms * lrms * lrms);
        
        if (improvebehave.verbosity > 5)
        {
            printf("V / lrms^3 ratio is %g, tetqual call is %g\n", opttet->vlrms3r, tetquality(mesh, opttet->verts[0],
                                                                                                     opttet->verts[1],
                                                                                                     opttet->verts[2],
                                                                                                     opttet->verts[3],
                                                                                                     improvebehave.qualmeasure));
        }
        
        /* compute gradient of lrms */
        vadd(t, u, gradlrms);
        vadd(v, gradlrms, gradlrms);
        vscale((-1.0 / (6.0 * lrms)), gradlrms, gradlrms);
        
        /* compute the terms of the gradient of the ratio */
        vscale((1.0 / (lrms * lrms * lrms)), volumegrad, vlrmsterm1);
        vscale((3.0 * volume) / (lrms * lrms * lrms * lrms), gradlrms, vlrmsterm2);
        
        /* add terms and normalize */
        vsub(vlrmsterm1, vlrmsterm2, opttet->vlrms3rgrad);
        vscale(normfac, opttet->vlrms3rgrad, opttet->vlrms3rgrad);
        
        /* if this is a facet or fixed vertex, 
           project gradient onto facet or plane */
        /*if (vtxkind == FACETVERTEX || vtxkind == FIXEDVERTEX)*/
        if (vtxkind == FACETVERTEX)
        {
            vprojecttoplane(opttet->vlrms3rgrad, vtxvec, opttet->vlrms3rgrad);
        }
    
        /* if this is a segment vertex, project gradient onto segment */
        if (vtxkind == SEGMENTVERTEX)
        {
            vproject(opttet->vlrms3rgrad, vtxvec, opttet->vlrms3rgrad);
        }
        
        if (improvebehave.verbosity > 5)
        {
            printf("vlrmsgrad is (%g %g %g)\n", opttet->vlrms3rgrad[0], opttet->vlrms3rgrad[1], opttet->vlrms3rgrad[2]);
        }
    }
    
}

/* test gradient computation */
bool testgrad(struct tetcomplex *mesh,
              tag vtx,
              tag vtx2,
              tag vtx3,
              tag vtx4)
{
    struct opttet tet;
    starreal *point, origpoint[3]; /* the vertex we're playing with */
    starreal change[3];
    starreal old, new, diff;
    int i,j,k,l;
    starreal grad[3];
    starreal epsilon = 1e-5;
    starreal onepe = 1+ epsilon;
    starreal oneme = 1- epsilon;
    
    point = ((struct vertex *) tetcomplextag2vertex(mesh, vtx))->coord;
    /* save the original point */
    vcopy(point,origpoint);
    
    tet.verts[0] = vtx;
    tet.verts[1] = vtx2;
    tet.verts[2] = vtx3;
    tet.verts[3] = vtx4;
    
    if (improvebehave.verbosity > 5) printf("\n****** BEGIN GRADIENT TEST *******\n");
    
    getoptinfo(mesh, &tet, FREEVERTEX, NULL);
    
    /* test volume gradient */
    old = tet.volume;
    if (improvebehave.verbosity > 5)
    {
        printf("    original volume is %g\n", tet.volume);
        printf("    volume gradient is %g %g %g\n", tet.volumegrad[0], tet.volumegrad[1], tet.volumegrad[2]);
        printf("        moving vertex 1%% of gradient...\n");
    }
    
    vcopy(tet.volumegrad, change);
    vscale(0.01, change, change);
    
    /* move the point */
    vadd(point, change, point);
    
    /* recalculate stuff */
    getoptinfo(mesh, &tet, FREEVERTEX, NULL);
    
    new = tet.volume;
    diff = new - old;
    
    /* put the original point back */
    vcopy(origpoint,point);
    
    if (improvebehave.verbosity > 5)
    {
        printf("    new volume is %g\n", new);
        printf("    difference is %g\n", diff);
    }
    
    if (diff < 0)
    {
        printf("\n\n\n!!!! ERROR, VOLUME DECREASED !!!!!\n\n\n");
        return false;
    }
    /************** end test volume gradient *********************/
    
        
    /************** test face area gradients *********************/
    if (improvebehave.verbosity > 5) printf("\n\n******** BEGIN FACE AREA GRADIENT TEST **********\n");
    for (i=0; i<4; i++)
    {
         /* put the original point back */
        vcopy(origpoint,point);
        getoptinfo(mesh, &tet, FREEVERTEX, NULL);
        
        old = tet.facearea[i];
        vcopy(tet.facegrad[i], grad);
        
        if (improvebehave.verbosity > 5)
        {
            printf("    original face area is %d is %g\n",i, old);
            printf("    face area gradient is %g %g %g\n", grad[0], grad[1], grad[2]);
            printf("        moving vertex...\n");
        }
        
        vcopy(grad, change);
        vscale(1e-7, change, change);
    
        /* move the point */
        vadd(point, change, point);
    
        /* recalculate stuff */
        getoptinfo(mesh, &tet, FREEVERTEX, NULL);
        
        new = tet.facearea[i];
        diff = new - old;
        
        if (improvebehave.verbosity > 5)
        {
            printf("    new face area is %d is %g\n",i, new);
            printf("    difference is %g\n", diff);
        }

        if (diff < 0)
        {
            printf("\n\n\n!!!! ERROR, FACE AREA DECREASED !!!!!\n\n\n");
            return false;
        }
    
    }
    /********************** end test face area gradients *********************/

    /************** test edge length gradients *********************/
    if (improvebehave.verbosity > 5) printf("\n\n******** BEGIN EDGE LENGTH GRADIENT TEST **********\n");
    for (i=0; i<6; i++)
    {
        for (j = i + 1; j < 4; j++) 
        {
            k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
            l = 6 - i - j - k;
            
            /* put the original point back */
            vcopy(origpoint,point);
            getoptinfo(mesh, &tet, FREEVERTEX, NULL);
        
            old = tet.edgelength[i][j];
            vcopy(tet.edgegrad[i][j], grad);
        
            if (improvebehave.verbosity > 5)
            {
                printf("    original edge length is %d is %g\n",i, old);
                printf("    edge length gradient is %g %g %g\n", grad[0], grad[1], grad[2]);
                printf("        moving vertex...\n");
            }
        
            vcopy(grad, change);
            vscale(1e-7, change, change);
    
            /* move the point */
            vadd(point, change, point);
    
            /* recalculate stuff */
            getoptinfo(mesh, &tet, FREEVERTEX, NULL);
        
            new = tet.edgelength[i][j];
            diff = new - old;
        
            if (improvebehave.verbosity > 5)
            {
                printf("    new edge length is %d is %g\n",i, new);
                printf("    difference is %g\n", diff);
            }

            if (diff < 0)
            {
                printf("\n\n\n!!!! ERROR, EDGE LENGTH DECREASED !!!!!\n\n\n");
                return false;
            }
        }
    
    }
    /********************** end test edge length gradients *********************/
    
    /* test sine gradients */
    if (improvebehave.verbosity > 5) printf("\n\n******** BEGIN SINE GRAIDENT TEST **********\n");
    for (i=0; i<6; i++)
    {
         /* put the original point back */
        vcopy(origpoint,point);
        getoptinfo(mesh, &tet, FREEVERTEX, NULL);
        
        old = tet.sine[i];
        
        /* if sine is really close to one, too unstable */
        if (old < onepe && old > oneme)
        {
            printf("sine really close to one, let it go...\n");
            continue;
        }
        
        if (improvebehave.verbosity > 5)
        {
            printf("    original sine %d is %g\n",i, old);
            printf("    sine gradient is %g %g %g\n", tet.sinegrad[i][0], tet.sinegrad[i][1], tet.sinegrad[i][2]);
            printf("        moving vertex...\n");
        }
        
        vcopy(tet.sinegrad[i], change);
        vscale(1e-10, change, change);
    
        /* move the point */
        vadd(point, change, point);
    
        /* recalculate stuff */
        getoptinfo(mesh, &tet, FREEVERTEX, NULL);
        
        new = tet.sine[i];
        diff = new - old;
        
        if (improvebehave.verbosity > 5)
        {
            printf("    new sine %d is %g\n",i, new);
            printf("    difference is %g\n", diff);
        

            printf("here's the tet:\n\n");
            printf("tet =");
            printtetverts(mesh,tet.verts);
            printf(";\n\n");
        
            printf("grad= [%f %f %f];\n", tet.sinegrad[i][0],tet.sinegrad[i][1],tet.sinegrad[i][2]);
        }

        if (diff < 0)
        {
            printf("\n\n\n!!!! ERROR, SINE DECREASED !!!!!\n");
            printopttet(&tet);
            
            return false;
        }
    
    }
    /* put the original point back */
    vcopy(origpoint,point);
    
    return 1;

}

/* returns the basis B of S union M. S is a set of points known
   to be in the basis */
void findbasis(starreal S[][3],
               starreal M[][3],
               starreal B[][3],
               int sizeS,
               int sizeM,
               int *sizeB)
{
    starreal p[3],q[3],r[3],s[3];        /* vertices */
    starreal s1[3], t1[3], d1[3], d2[3]; /* temporary vertices */
    starreal origin[3] = {0.0, 0.0, 0.0};
    starreal localS[4][3];               /* for passing to recursive calls */
    starreal localM[MAXINCIDENTTETS][3]; /* for passing to recursive colls */
    
    assert(sizeM > 0);
    
    if (improvebehave.verbosity > 5) printbasisarrays(S,M,B,sizeS,sizeM,sizeB,p);
    
    /* we assume that M was passed to us shuffled, so that taking
       the last element is equivalent to removing a random one. */
    vcopy(M[sizeM-1],p);
    
    /* if M has only one element */
    if (sizeM == 1)
    {
        /* and S has no elements */
        if (sizeS == 0)
        {
            if (improvebehave.verbosity > 5) printf("M has one element, and S is empty. Copying M to B and sending it back...\n");
            
            /* then the single element in M must be the
               entire basis, just send back M */
            pointarraycopy(M, B, 1);
            *sizeB = 1;
            return;
        }
        
        if (improvebehave.verbosity > 5) printf("M has one element p. Assume it's not in basis and set B = S...\n");
        
        /* otherwise, because we assume the last element
           we just removed is not part of the basis, assign
           the basis to be the elements of S */
        pointarraycopy(S, B, sizeS);
        *sizeB = sizeS;
    }
    /* M has more than one element. Throw one out (p), and look for the
       basis assuming p is not part of it. */
    else
    {
        if (improvebehave.verbosity > 5) printf("M has more than one element, tossing one out and recursing...\n");
        
        /* make a new copy of M minus the last element */
        pointarraycopy(M, localM, sizeM-1);
        pointarraycopy(S, localS, sizeS);
        findbasis(localS, localM, B, sizeS, sizeM-1, sizeB);
    }
    
    /* now the we have determined the basis without p, we need to 
       go back and check whether p actually is part of the basis. */
    
    switch (*sizeB)
    {
        /* if the returned basis has just one point q, we just need to check
           whether p is closer to the origin than q */
        case 1:
            /* fetch the actual coordinates from the mesh */
            vcopy(B[0],q);
        
            /* compute the vector from q to p */
            vsub(p, q, d1);
            
            /* check the sign of the dot product. >=0 means p doesn't
               improve the basis */
            if (dot(q,d1) >= 0)
            {
                /* this is a good B, send it back!*/
                return;
            }
            break;
            
        /* check whether p improves the basis using math I don't understand */        
        case 2:
            /* fetch coordinates from the mesh */
            vcopy(B[0],q);
            vcopy(B[1],r);
            
            /* compute vector s from r to p */
            vsub(p, r, s1);
            /* compute vector t from r to q */
            vsub(q, r, t1);
            
            /* now a couple of cross products */
            cross(s1, t1, d1);
            cross(r, t1, d2);
            
            /* can p improve the basis? */
            if (dot(d1,d2) >= 0)
            {
                /* nope! send back B as is. */
                return;
            }            
            break;
        case 3:
            /* fetch coordinates from the mesh */
            vcopy(B[0],q);
            vcopy(B[1],r);
            vcopy(B[2],s);
            
            /* does p improve the basis? */
            if (orient3d(&behave, p, q, r, s) * orient3d(&behave, origin, q, r, s) <= 0)
            {
                /* nope! send back B as is. */
                return;
            }
            break;
        default:
            /* B has size of 4, and any basis of this size is optimal */
            return;
            break;
    }
    
    /* if we have made it this far, we know that p actually is a part of
       any basis of S union M */
       
    /* if p was the last element of M, or if S already has three other basis
       points, we're done and just need to send back S union p. */
    if ((sizeM == 1) || (sizeS == 3))
    {
        if (improvebehave.verbosity > 5) printf("p in basis and it's the last possible point, return S U p\n");
        /* the final size of B is the size of S + 1 */
        *sizeB = sizeS + 1;
        /* copy S into B */
        pointarraycopy(S, B, sizeS);
        /* and add p at the end */
        vcopy(p, B[*sizeB - 1]);
        
        return;
    }
    /* there may be more basis points to find! move p from M to the known
       basis point set S, and go again */
    else
    {
        if (improvebehave.verbosity > 5)
        {
            printf("p in basis, more points to check. Moving p from M to S\n");
            printf("here's how everything looked before the move:\n");
            printbasisarrays(S,M,B,sizeS,sizeM,sizeB,p);
        } 
        
        /* create the new S */
        pointarraycopy(S, localS, sizeS);
        /* add p to the end of it */
        vcopy(p, localS[sizeS]);
        
        /* create the new M, leaving off the last element */
        pointarraycopy(M, localM, sizeM-1);
        
        /* find any basis points remaining in M */
        findbasis(localS, localM, B, sizeS+1, sizeM-1, sizeB);
        
        return;
    }        
}

/* finds the point on the convex hull of P nearest
   the origin */
void minconvexhullpoint(starreal P[][3],
                        int sizeP,
                        starreal nearest[])
{
    starreal B[4][3];                /* the basis for the convex hull point */
    int sizeB=0;                   /* size of the basis */
    starreal empty[4][3];            /* empty set for known basis */
    starreal *p, *q, *r;             /* basis points */
    starreal pmq[3];                 /* p minus q */
    starreal c, d, l;                /* scalar factors */
    starreal s[3], t[3], s2[3], t2[3];/* temporary points */
    starreal sxt[3], sxr[3], rxt[3], temp[3]; /* temporary cross products */
    int i;
    
    assert(sizeP > 0);
    
    /* find a basis for the minimum point on the convex hull */
    findbasis(empty, P, B, 0, sizeP, &sizeB);
    
    if (improvebehave.verbosity > 5)
    {
        printf("\nbasis size is %d\n", sizeB);
        printf("here are the basis points:\nbasis=[");
        for (i=0; i<sizeB; i++)
        {
            printf("%.17g %.17g %.17g;\n",B[i][0],B[i][1],B[i][2]);
        }
        printf("]\n");
        
    }
    
    switch(sizeB)
    {
        /* if the basis is just a single point, return that point */
        case 1:
            vcopy(B[0], nearest);
            return;
            break;
        /* for two points, find the closest point to the origin on
           the line between the two points */
        case 2:
            p = B[0];
            q = B[1];
            vsub(p,q,pmq);
            
            /*
              nearest = q - dot(q,p-q)/(length(p-q)^2) * (p-q)
            */
            l = vlength(pmq);
            
            /* if these points are the same, just return one of them */
            if (l == 0.0)
            {
                vcopy(B[0], nearest);
                return;
            }
            
            c = dot(q,pmq) / (l * l);
            vscale(c,pmq,nearest);
            vsub(q,nearest,nearest);
            
            return; 
            break;
        /* for three points, find the point closest to the origin
           on the triangle that the they form */
        case 3:
            p = B[0];
            q = B[1];
            r = B[2];
            
            vsub(p,r,s);
            vsub(q,r,t);
            
            cross(s,t,sxt);
            cross(r,t,rxt);
            cross(s,r,sxr);
            
            /* if any of these cross products is really tiny, give up
               and return the origin */
            if (vlength(sxt) < NEARESTMIN || vlength(rxt) < NEARESTMIN || vlength(sxr) < NEARESTMIN)
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("Encountered tiny factor (< %g) in nearest point computation, returning origin.\n", NEARESTMIN);
                    printf("sxt= %.17g %.17g %.17g\n", sxt[0], sxt[1], sxt[2]);
                    printf("rxt= %.17g %.17g %.17g\n", rxt[0], rxt[1], rxt[2]);
                    printf("sxr= %.17g %.17g %.17g\n", sxr[0], sxr[1], sxr[2]);
                }
                nearest[0] = 0.0;
                nearest[1] = 0.0;
                nearest[2] = 0.0;
                return;
            }
            
            c = dot(sxt,rxt) / dot(sxt,sxt);
            d = dot(sxt,sxr) / dot(sxt,sxt);
            
            vscale(c,s,s2);
            vscale(d,t,t2);
            
            vsub(r,s2,temp);
            vsub(temp,t2,nearest);
            
            return;
            break;
        /* if the basis has four points, they must enclose the origin
           so just return the origin. */
        case 4:
            nearest[0] = 0.0;
            nearest[1] = 0.0;
            nearest[2] = 0.0;
            return;
            break;
        default:
            printf("Error, basis size %d is bogus, dying\n",sizeB);
            starexit(1);
            break;
    }
}



/* find the best step to take to improve all of the quality
   functions affected by a vertex vtx in the search direction
   d with an expected rate of improvement r */
void nonsmoothlinesearch(struct tetcomplex *mesh,
                         tag vtx,
                         starreal d[],
                         starreal inworstqual,
                         starreal *alpha,
                         starreal r,
                         struct opttet incidenttets[],
                         int numincident,
                         int vtxkind,
                         starreal vtxvec[3])
{
    int numiter = 0;      /* number of iterations */
    starreal *v;            /* the vertex to be modified */
    starreal origvertex[3]; /* to save the original vertex position */
    starreal offset[3];     /* the offset to move the vertex, alpha * d */
    starreal worstqual;     /* the current worst quality */
    starreal origworstqual; /* the original worst quality */
    starreal thisqual;    /* the quality of the current tet */
    starreal oldworstqual;  /* the worst quality at the last step */
    int i;                /* loop index */
    
    /* save the original worst quality */
    origworstqual = oldworstqual = inworstqual;
    
    /* fetch the original vertex coordinates from the mesh */
    v = ((struct vertex *) tetcomplextag2vertex(mesh, vtx))->coord;
    vcopy(v, origvertex);
    
    /* keep trying until alpha gets too small or we exceed maximum
       number of iterations */
    while ((*alpha > MINSTEPSIZE) && (numiter < MAXLINEITER))
    {
        if (improvebehave.verbosity > 5) printf("In line search, alpha=%g numiter=%d\n",*alpha,numiter);
        
        /* compute the offset from original vertex positon,
           alpha * d */
        vscale(*alpha, d, offset);
        /* move the vertex */
        vadd(v, offset, v);
        
        /* recompute all of the quality functions affected
           by v's position, taking note of the smallest one */
        worstqual = HUGEFLOAT; 
        for (i=0; i<numincident; i++)
        {
            thisqual = tetquality(mesh,
                                  incidenttets[i].verts[0],
                                  incidenttets[i].verts[1],
                                  incidenttets[i].verts[2],
                                  incidenttets[i].verts[3],
                                  improvebehave.qualmeasure);
        
            if (improvebehave.verbosity > 5 && thisqual < 0.0)
            {
                printf("in line search, after taking step we have negative quality = %g\n", thisqual);
            }
            
            /* is this the worst quality we've seen? */
            if (thisqual < worstqual) worstqual = thisqual;
        }
        
        /* if we're using surface quadrics */
        if (improvebehave.usequadrics && hasquadric(vtx) && ((struct vertextype *) arraypoolforcelookup(&vertexinfo, vtx))->kind == FIXEDVERTEX)
        /* if (improvebehave.usequadrics && hasquadric(vtx) && ((struct vertextype *) arraypoolforcelookup(&vertexinfo, vtx))->kind != FREEVERTEX) */
        {
            /* check whether the surface quadric is the worse than all the tets */
            starreal qe = quadricerrortet(mesh, vtx);
            if (qe < worstqual) 
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("In line search, vertex %d's quadric error (%g raw, %g normalized) is worse than any tet quality!\n", (int) vtx, quadricerror(mesh, vtx), qe);
                }
                worstqual = qe;
            }
        }
        
        
        if (improvebehave.verbosity > 5) printf("The old worst was %g, the new worst is %g, diff is %g\n",oldworstqual,worstqual,worstqual-oldworstqual);
            
            /* if this is not the first iteration, and
           we did better on the last iteration, use
           the step size from the previous iteration */
        if ((oldworstqual > origworstqual) && (oldworstqual > worstqual))
        {
            if (improvebehave.verbosity > 5) printf("last step did better than current alpha, return it.\n");
            
            /* use the previous step's alpha */
            *alpha = (*alpha) * 2;
            assert(*alpha > 0.0);
            
            /* put vertex back where it started */
            vcopy(origvertex, v);
            
            return;
        }
        
        /* if we have succeeded in gaining 90% of the expected
           improvement, accept this initial step size */
        if ((worstqual - origworstqual) > (0.9 * (*alpha) * r))
        {
            if (improvebehave.verbosity > 5) printf("diff between origworstqual=%g and curworstqual=%g is >90%% expected improvement %g.\nthis step is a success, return alpha=%g\n",origworstqual,worstqual,*alpha * r * 0.9, *alpha);
            
            /* put vertex back where it started */
            vcopy(origvertex, v);
            
            return;
        }
        
        if (improvebehave.verbosity > 5) printf("this alpha isn't working, going to half it...\n");
        
        /* put vertex back where it started */
        vcopy(origvertex, v);
        
        /* cut alpha down by half and try again */
        *alpha = (*alpha) / 2.0;
        
        /* save the worst quality from this step */
        oldworstqual = worstqual;
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("whoa, failed to find an appropriate alpha! numiter = %d, alpha = %g\n", numiter, *alpha);
    }
    
    /* no positive alpha could be found that improved things... give up and return zero */
    *alpha = 0.0;
}



/* given a set of tets incident to a vertex, and the quality
   of the worst quality function that varies with that vertex,
   compute the active set A of quality functions very near
   the worst */
void getactiveset(struct tetcomplex *mesh,
                  struct opttet incidenttets[],
                  int numincident,
                  starreal activegrads[][3],
                  int *numactive,
                  starreal worstqual)
{
    int i,j;
    tag vtx = incidenttets[0].verts[0];
    
    /* reset number of active gradients to zero */
    *numactive = 0;
    
    if (improvebehave.verbosity > 5)
    {
        printf("worstqual is %g\n", worstqual);
    }
    
    /* if we are including surface quadrics, give them a chance to
       enter the active set */
    assert(numincident > 0);
    /* if (improvebehave.usequadrics && hasquadric(vtx) && ((struct vertextype *) arraypoolforcelookup(&vertexinfo, vtx))->kind != FREEVERTEX) */
    if (improvebehave.usequadrics && hasquadric(vtx) && ((struct vertextype *) arraypoolforcelookup(&vertexinfo, vtx))->kind == FIXEDVERTEX)
    {
        /* if the quadric is close enough to worst, add it to the active set */
        if (quadricerrortet(mesh, vtx) <= (worstqual * ACTIVESETFACTOR))
        {
            /* fetch the gradient of this quadric */
            starreal quadgrad[3];
            quadricgradtet(mesh, vtx, quadgrad);
            
            if (improvebehave.verbosity > 5)
            {
                printf("Vertex %d's quadric error (%g raw, %g normalized, gradient = [%g %g %g]) is in the active set (worstqual = %g)!\n", (int) vtx, quadricerror(mesh, vtx), quadricerrortet(mesh, vtx), quadgrad[0], quadgrad[1], quadgrad[2], worstqual);
            }
            
            /* copy the gradient into the list of active gradients */
            vcopy(quadgrad, activegrads[*numactive]);
            (*numactive)++;
        }
    }
    
    for (i=0; i<numincident; i++)
    {
        switch (improvebehave.qualmeasure)
        {
            case QUALWARPEDMINSINE:
            case QUALMINSINE:
                for (j=0; j<6; j++)
                {
                    /* is this close enough to the worst? */
                    if (incidenttets[i].sine[j] < (worstqual * ACTIVESETFACTOR))
                    {
                        /* get the actual gradient value */
                        vcopy(incidenttets[i].sinegrad[j], activegrads[*numactive]);
                
                        (*numactive)++;
                    }
                }
                break;
            case QUALRADIUSRATIO:
                if (improvebehave.verbosity > 5)
                {
                    printf("rnrr for tet %d is %g\n", i, incidenttets[i].rnrr);
                }
                
                if (incidenttets[i].rnrr <= (worstqual * ACTIVESETFACTOR))
                {
                    /* get the actual gradient value */
                    vcopy(incidenttets[i].rnrrgrad, activegrads[*numactive]);
                    
                    (*numactive)++;
                }
                break;
            case QUALVLRMS3RATIO:
                if (improvebehave.verbosity > 5)
                {
                    printf("vlrms3r for tet %d is %g\n", i, incidenttets[i].vlrms3r);
                }

                if (incidenttets[i].vlrms3r <= (worstqual * ACTIVESETFACTOR))
                {
                    /* get the actual gradient value */
                    vcopy(incidenttets[i].vlrms3rgrad, activegrads[*numactive]);

                    (*numactive)++;
                }
                break;
            default:
                printf("i don't know how to compute the active set for qual measure %d\n", improvebehave.qualmeasure);
                starexit(1);
                break;
        }
    }
    
    if (*numactive == 0)
    {
        printf("didn't find any active quality functions.");
        for (i=0; i<numincident; i++)
        {
            printopttet(&incidenttets[i]);
        }
    }
    
    /* we must have at least found the worst */
    /* assert(*numactive > 0); */
}

/* for our initial step size, we use the distance
   to the next intersection with another quality funtion.
   this is the point at which the other quality function
   becomes the worst. we use a single-term taylor expansion
   to approximate all of the quality functions as lines,
   so we'll have to do a line search to find our ultimate
   step size. */
starreal getinitialalpha(struct tetcomplex *mesh,
                         struct opttet incidenttets[],
                         int numincident,
                         starreal d[3],
                         starreal r,
                         starreal worstqual)
{
    int i,j;
    starreal alpha = HUGEFLOAT;
    starreal newalpha;
    starreal rate;
    tag vtx = incidenttets[0].verts[0];
    
    /* if we are including surface quadrics add check for it */
    assert(numincident > 0);
    /* if (improvebehave.usequadrics && hasquadric(vtx) && ((struct vertextype *) arraypoolforcelookup(&vertexinfo, vtx))->kind != FREEVERTEX) */
    if (improvebehave.usequadrics && hasquadric(vtx) && ((struct vertextype *) arraypoolforcelookup(&vertexinfo, vtx))->kind == FIXEDVERTEX)
    {
        /* fetch the gradient of this quadric */
        starreal quadgrad[3];
        quadricgradtet(mesh, vtx, quadgrad);
        
        /* if this function improves more slowly
           than any in the active set, then it might
           end up as the objective. */
        rate = dot(d, quadgrad);
        if (rate + RATEEPSILON < r)
        {
            /* compute the approximation of when this
               function will become the objective */
            newalpha = (quadricerrortet(mesh, vtx) - worstqual) / (r - rate);
    
            /* if this is smaller than our current step size,
               use it for the step size */
            if (newalpha < alpha)
            {
                alpha = newalpha;
                if (improvebehave.verbosity > 5)
                {
                    printf("Vertex %d's quadric error sets initial alpha (%g raw, %g normalized, gradient = [%g %g %g])\n", (int) vtx, quadricerror(mesh, vtx), quadricerrortet(mesh, vtx), quadgrad[0], quadgrad[1], quadgrad[2]);
                }
            }
        }
    }
    
    for (i=0; i<numincident; i++)
    {
        switch (improvebehave.qualmeasure)
        {
            case QUALWARPEDMINSINE:
            case QUALMINSINE:
                for (j=0; j<6; j++)
                {
                    /* if this function improves more slowly
                       than any in the active set, then it might
                       end up as the objective. */
                    rate = dot(d,incidenttets[i].sinegrad[j]);
                    if (rate + RATEEPSILON < r)
                    {
                        /* compute the approximation of when this
                           function will become the objective */
                        newalpha = (incidenttets[i].sine[j] - worstqual) / (r - rate);
                
                        /* if this is smaller than our current step size,
                           use it for the step size */
                        if (newalpha < alpha)
                        {
                            alpha = newalpha;
                        }
                    }
                }
                break;
            case QUALRADIUSRATIO:
                /* if this function improves more slowly
                   than any in the active set, then it might
                   end up as the objective. */
                rate = dot(d,incidenttets[i].rnrrgrad);
                if (rate + RATEEPSILON < r)
                {
                    /* compute the approximation of when this
                       function will become the objective */
                    newalpha = (incidenttets[i].rnrr - worstqual) / (r - rate);
            
                    /* if this is smaller than our current step size,
                       use it for the step size */
                    if (newalpha < alpha)
                    {
                        alpha = newalpha;
                    }
                }
                break;
            case QUALVLRMS3RATIO:
                /* if this function improves more slowly
                   than any in the active set, then it might
                   end up as the objective. */
                rate = dot(d,incidenttets[i].vlrms3rgrad);
                if (rate + RATEEPSILON < r)
                {
                    /* compute the approximation of when this
                       function will become the objective */
                    newalpha = (incidenttets[i].vlrms3r - worstqual) / (r - rate);

                    /* if this is smaller than our current step size,
                       use it for the step size */
                    if (newalpha < alpha)
                    {
                        alpha = newalpha;
                    }
                }
                break;
            default:
                printf("i don't know how to compute alpha for qual measure %d\n", improvebehave.qualmeasure);
                starexit(1);
                break;
        }
    }
    
    if (improvebehave.anisotropic == false)
    {
        assert(alpha > 0.0);
    }
    else if (alpha < 0.0)
    {
        alpha = 0.0;
    }
    return alpha;
}

/* perform non-smooth optimization of a vertex's position.
   vtx - the vertex to be smoothed, is in tet (vtx, vtx2, vtx3, vtx4).
   This tet gives us a starting point to build the list of incident
   elements.
   
   If we end up moving the vertex, return true.
   If for some reason we can't, return false.
*/
bool nonsmooth(struct tetcomplex *mesh,
               tag vtx,
               struct opttet incidenttets[],
               int numincident,
               starreal *outworstqual,
               int smoothkinds)
{
    starreal *v;           /* the vertex to be altered */
    starreal origpoint[3]; /* to save the original vertex location */
    int numactive;         /* number of quality functions in the active set */
    int i,k;               /* loop index */
    int numiter = 0;       /* number of optimization iterations */
    starreal worstqual;      /* the numerical value of the worst quality function */
    starreal thisqual;       /* quality of the current tet */
    starreal oldworstqual;   /* the numerical value of the worst quality function at the last step */
    starreal improvement;    /* how much we've improved this step */
    starreal d[3];           /* direction to move vertex */
    starreal dlength;        /* length of d */
    starreal r;              /* expected rate of improvement */
    starreal newr;           /* temp r var */
    starreal alpha;          /* step size */
    starreal newalpha;       /* candidate new step size */
    starreal rate;           /* the rate a particular function will improve in the direction d */
    starreal change[3];      /* change we'll make to the point */
    struct vertextype *vinfo;
    tag verts[4];
    starreal qe;
    starreal allgrads[3];
    /* the gradients in the active set */
    starreal activegrads[MAXINCIDENTTETS][3];
    
    vinfo = (struct vertextype *) arraypoolforcelookup(&vertexinfo, vtx);
    
    /* if fixed vertex smoothing is enabled, and this vertex is a facet
       or segment vertex, we need to check that it still is */
    if ((vinfo->kind == FACETVERTEX || vinfo->kind == SEGMENTVERTEX) &&
        improvebehave.fixedsmooth)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("Reclassifying in smooth, old type is %d", vinfo->kind);
        }
        
        /* reset this vertex type */
        vinfo->kind = INPUTVERTEX;
        
        /* reclassify this vertex */
        assert(incidenttets[0].verts[0] == vtx);
        tetvertexclassify(mesh, vtx, incidenttets[0].verts[1], incidenttets[0].verts[2], incidenttets[0].verts[3]);
        
        if (improvebehave.verbosity > 5)
        {
            printf(" new type is %d\n", vinfo->kind);
        }
    }
    
    /* check whether to try to smooth facet/segment/fixed vertices */
    if (vinfo->kind == FACETVERTEX && ((smoothkinds & SMOOTHFACETVERTICES) == 0))
    {
        return false;
    }
    if (vinfo->kind == SEGMENTVERTEX && ((smoothkinds & SMOOTHSEGMENTVERTICES) == 0))
    {
        return false;
    }
    if (vinfo->kind == FIXEDVERTEX && ((smoothkinds & SMOOTHFIXEDVERTICES) == 0))
    {
        return false;
    }
    
    switch (vinfo->kind)
    {
        case FREEVERTEX:
            stats.freesmoothattempts++;
            break;
        case FACETVERTEX:
            stats.facetsmoothattempts++;
            break;
        case SEGMENTVERTEX:
            stats.segmentsmoothattempts++;
            break;
        case FIXEDVERTEX:
            stats.fixedsmoothattempts++;
            break;
        default:
            printf("i don't know vertex type %d, dying\n", vinfo->kind);
            starexit(1);
    }
    stats.nonsmoothattempts++;
    
    /* get vertex to be altered */
    v = ((struct vertex *) tetcomplextag2vertex(mesh, vtx))->coord;
    
    /* save the original position of the vertex */
    vcopy(v, origpoint);
    
    /* find the worst quality of all incident tets */
    worstqual = HUGEFLOAT; 
    for (i=0; i<numincident; i++)
    {
        thisqual = tetquality(mesh,
                              incidenttets[i].verts[0],
                              incidenttets[i].verts[1],
                              incidenttets[i].verts[2],
                              incidenttets[i].verts[3],
                              improvebehave.qualmeasure);
        
        /* is this the worst quality we've seen? */
        if (thisqual < worstqual) worstqual = thisqual;
    }
    
    if (worstqual <= 0.0)
    {
        printf("Starting up smoothing, input tet has quality %g\n", worstqual);
    }
    assert(worstqual > 0.0);
    
    /* if we're using surface quadrics */
    /* if (improvebehave.usequadrics && vinfo->kind != FREEVERTEX) */
    if (improvebehave.usequadrics && vinfo->kind == FIXEDVERTEX)
    {
        /* this vertex had better have an initialized quadric */
        assert(hasquadric(vtx));
        
        /* check whether the surface quadric is the worse than all the tets */
        qe = quadricerrortet(mesh, vtx);
        if (qe < worstqual) 
        {
            if (improvebehave.verbosity > 5)
            {
                printf("Vertex %d's quadric error (%g raw, %g normalized) is worse than any tet quality!\n", (int) vtx, quadricerror(mesh, vtx), qe);
            }
            worstqual = qe;
        }
    }
    
    *outworstqual = worstqual;
    
    allgrads[0] = allgrads[1] = allgrads[2] = 0.0;
    
    /* if this is a fixed vertex, we have to compute the plane that it
         can move in first. do this by first getting the volume gradient for all tets */
    /* we're not doing this for now, vertices are free to move anywhere */
    if (vinfo->kind == FIXEDVERTEX && false)
    {
        for (i=0; i<numincident; i++)
        {
            /* compute gradient info for this tet, faking that it's free */
            getoptinfo(mesh, &incidenttets[i], FREEVERTEX, vinfo->vec);
            /* accumulate the volume gradients as we go */
            vadd(incidenttets[i].volumegrad, allgrads, allgrads);
        }
        /* normalize the summed gradient vector */
        vscale(1.0 / vlength(allgrads), allgrads, allgrads);
        vcopy(allgrads, vinfo->vec);
        
        if (improvebehave.verbosity > 5)
        {
            printf("here are the incident tets:\n");
            printopttets(mesh, incidenttets, numincident);
            printf("normal to the constant volume plane is (%g %g %g)\n",  vinfo->vec[0], vinfo->vec[1], vinfo->vec[2]);
        }
    }
    
    /* identify the active set A of quality functions that are
       nearly as bad as f, the worst of them all */
    for (i=0; i<numincident; i++)
    {
        /* compute gradient info for this tet */
        getoptinfo(mesh, &incidenttets[i], vinfo->kind, vinfo->vec);
    }
    getactiveset(mesh,
                 incidenttets,
                 numincident,
                 activegrads,
                 &numactive,
                 worstqual);
    if (improvebehave.anisotropic == false)
    {
        assert(numactive > 0);
    }
    else if (numactive == 0)
    {
        return false;
    }
    
    /* d <- point on the convex hull of all gradients nearest origin */
    minconvexhullpoint(activegrads, numactive, d);
    
    /* if d is the origin, we can't improve this vertex with smoothing. */
    dlength = vlength(d);
    if (dlength < DEPSILON)
    {
        return false;
    }
    
    if (improvebehave.verbosity > 5 && vinfo->kind == FIXEDVERTEX)
    {
        starreal normald[3];
        vscale(1.0 / dlength, d, normald);
        printf("the search direction (length %g) for fixed is (%g, %g, %g)\n", dlength, normald[0], normald[1], normald[2]);
    }
    
    /* otherwise, it's time to do some smoothing! */
    do
    {
        /* find r, the expected rate of improvement. r is computed as the minimum
           dot product between the improvment direction d and all of the active 
           gradients, so it's like "how fast do we move in the direction of the
           gradient least favored by d." */
        
        /* start with an absurdly big r */
        r = HUGEFLOAT;
        /* find the smallest dot product */
        for (i=0; i<numactive; i++)
        {
            newr = dot(d,activegrads[i]);
            
            if (newr <= 0.0)
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("\n\n r=%g is negative, hmm.\n",newr);
                    printf("d is (%g %g %g)\n", d[0], d[1], d[2]);
                    printf("the gradient in question i=%d is (%.17g %.17g %.17g)\n",i,activegrads[i][0],activegrads[i][1],activegrads[i][2]);
                    printf("here are all the gradients:\ngrads=[");
                    for(k=0; k<numactive; k++)
                    {
                        printf("%.17g %.17g %.17g;\n", activegrads[k][0],activegrads[k][1],activegrads[k][2]);
                    }
                    printf("]\nd=[%.17g %.17g %.17g]\n", d[0], d[1], d[2]);
                }
                
                /* if we have already moved the vertex some, this is still a success */
                if (vequal(v, origpoint) == false)
                {
                        /* record this change in the journal */
                        
                        verts[0] = vtx;
                        verts[1] = incidenttets[0].verts[1];
                        verts[2] = incidenttets[0].verts[2];
                        verts[3] = incidenttets[0].verts[3];
                        
                        insertjournalentry(mesh, SMOOTHVERTEX, verts, 4, origpoint, v);
                        
                        *outworstqual = worstqual;
                        
                        if (improvebehave.verbosity > 5)
                        {
                            textcolor(BRIGHT, RED, BLACK);
                            printf("Just recorded a smooth that ended with d going bad!\n");
                            textcolor(RESET, WHITE, BLACK);
                        }
                        
                        /* record stats */
                        switch (vinfo->kind)
                        {
                            case FREEVERTEX:
                                stats.freesmoothsuccesses++;
                                break;
                            case FACETVERTEX:
                                stats.facetsmoothsuccesses++;
                                break;
                            case SEGMENTVERTEX:
                                stats.segmentsmoothsuccesses++;
                                break;
                            case FIXEDVERTEX:
                                stats.fixedsmoothsuccesses++;
                                break;
                            default:
                                printf("i don't know vertex type %d, dying\n", vinfo->kind);
                                starexit(1);
                        }
                        stats.nonsmoothsuccesses++;
                        return true;
                }
                else
                {
                    return false;
                }
            }
            
            /* this had better be positive */
            assert(newr > 0.0);
            
            if (newr < r)
            {
                r = newr;
            }
        }
        
        /* save the worst quality from the previous step */
        oldworstqual = worstqual;
        
        /* initialize alpha to the nearest intersection with another
           quality function */
        alpha = getinitialalpha(mesh,
                                incidenttets,
                                numincident,
                                d, r, worstqual);
        
        if (improvebehave.anisotropic == false)
        {
            assert(alpha > 0.0);
        }
        else
        {
            assert(alpha >= 0.0);
        }

        /* if we didn't find a limit for alpha above, at least limit it
           so that we don't invert any elements. */
        if (alpha == HUGEFLOAT)
        {
            if (improvebehave.verbosity > 5) printf("using volume gradients to pick alpha...\n");
            
            for (i=0; i<numincident; i++)
            {
                /* if moving in the direction d will decrease 
                   this element's volume */
                rate = dot(d,incidenttets[i].volumegrad);
                if (rate < 0.0)
                {
                    newalpha = -incidenttets[i].volume / (2.0 * rate);
                    
                    /* if this is smaller than the current step size,
                       use it */
                    if (newalpha < alpha)
                    {
                        alpha = newalpha;
                    }
                }
            }
        }
        
        if (improvebehave.verbosity > 5) printf("In non-smooth opt, found alpha_0 = %g, numiter = %d\n", alpha, numiter);
        
        /* do normal line search */
        nonsmoothlinesearch(mesh, vtx, d, worstqual, &alpha, r, incidenttets, numincident, vinfo->kind, vinfo->vec);
        assert(alpha >= 0.0);
        
        /* move vertex in direction d step size alpha */
        vscale(alpha, d, change);
        vadd(v, change, v);
         
        /* recompute quality information */
        oldworstqual = worstqual;
        worstqual = HUGEFLOAT; 
        for (i=0; i<numincident; i++)
        {
            thisqual = tetquality(mesh,
                                  incidenttets[i].verts[0],
                                  incidenttets[i].verts[1],
                                  incidenttets[i].verts[2],
                                  incidenttets[i].verts[3],
                                  improvebehave.qualmeasure);
            
            if (thisqual < 0.0)
            {
                printf("Just smooothed a vertex then found a tet with negative quality.\n");
                printf("alpha = %g\n", alpha);
            }
            
            /* is this the worst quality we've seen? */
            if (thisqual < worstqual) worstqual = thisqual;
        }
        
        /* if we're using surface quadrics */
        /* if (improvebehave.usequadrics && vinfo->kind != FREEVERTEX) */
        if (improvebehave.usequadrics && vinfo->kind == FIXEDVERTEX)
        {
            /* this vertex had better have an initialized quadric */
            assert(hasquadric(vtx));

            /* check whether the surface quadric is the worse than all the tets */
            qe = quadricerrortet(mesh, vtx);
            if (qe < worstqual) 
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("Vertex %d's quadric error (%g raw, %g normalized) is worse than any tet quality AFTER vertex move!\n", (int) vtx, quadricerror(mesh, vtx), qe);
                }
                worstqual = qe;
            }
        }
        
        if (improvebehave.verbosity > 5 || worstqual < 0.0) printf("After moving vertex worstqual went from %g to %g, diff of %g\n\n",oldworstqual,worstqual,worstqual-oldworstqual);
        
        assert(worstqual >= 0.0);
        
        /* how much did we improve this step? */
        improvement = worstqual - oldworstqual;
        /*if (improvement < 0)*/
        if (1 == 0)
        {    
            textcolor(BRIGHT, RED, BLACK);
            printf("whoa, negative improvement!\n");
            printf("In non-smooth opt, found alpha_0 = %g, numiter = %d\n", alpha, numiter);
            printf("After moving vertex worstqual went from %g to %g, diff of %g\n\n",oldworstqual,worstqual,worstqual-oldworstqual);
            textcolor(RESET, WHITE, BLACK);
            
            /* move point back to original position */
            vcopy(origpoint, v);
            return false;
        }
        assert(improvement >= 0);
        
        /* recompute the active set */
        for (i=0; i<numincident; i++)
        {
            /* compute gradient info for this tet */
            getoptinfo(mesh, &incidenttets[i], vinfo->kind, vinfo->vec);
        }
        getactiveset(mesh,
                     incidenttets,
                     numincident,
                     activegrads,
                     &numactive,
                     worstqual);
        assert(numactive > 0);
        
        /* d <- point on the convex hull of all gradients nearest origin */
        minconvexhullpoint(activegrads, numactive, d);
        
        numiter++;
        
        dlength = vlength(d);
    } while ((dlength > DEPSILON) && 
             (numiter < MAXSMOOTHITER) &&
             (improvement > MINSMOOTHITERIMPROVE));
    
    if (improvebehave.verbosity > 5)
    {
        printf("finished optimizing a vertex. d=(%g, %g, %g), numiter=%d, improvement=%g\n\n",d[0],d[1],d[2],numiter,improvement);
    }
    
    /* record this change in the journal */
    verts[0] = vtx;
    verts[1] = incidenttets[0].verts[1];
    verts[2] = incidenttets[0].verts[2];
    verts[3] = incidenttets[0].verts[3];
    
    insertjournalentry(mesh, SMOOTHVERTEX, verts, 4, origpoint, v);
    
    *outworstqual = worstqual;
    
    /* record stats */
    switch (vinfo->kind)
    {
        case FREEVERTEX:
            stats.freesmoothsuccesses++;
            break;
        case FACETVERTEX:
            stats.facetsmoothsuccesses++;
            break;
        case SEGMENTVERTEX:
            stats.segmentsmoothsuccesses++;
            break;
        case FIXEDVERTEX:
            stats.fixedsmoothsuccesses++;
            break;
        default:
            printf("i don't know vertex type %d, dying\n", vinfo->kind);
            starexit(1);
    }
    stats.nonsmoothsuccesses++;
    return true;
}

/* optimization-based smoothing for a single vertex
   v1, part of the existing tet (1,2,3,4) */
bool nonsmoothsinglevertex(struct tetcomplex *mesh,
                        tag v1,
                        tag v2,
                        tag v3,
                        tag v4,
                        starreal *worstout,
                        int kinds)
{
    int numincident = 0;
    bool noghosts = true;
    int incIter;
    bool smoothed;
    
    /* a list of all the tets incident to this vertex */
    tag incidenttettags[MAXINCIDENTTETS][4];
    /* a list of information about all the incident tets */
    struct opttet incidenttets[MAXINCIDENTTETS];
    
    if (tetexists(mesh, v1, v2, v3, v4) == false)
    {
        return false;
    }
    
    /* don't smooth if smoothing disabled */
    if (improvebehave.nonsmooth == 0) return false;
    
    getincidenttets(mesh, 
                    v1,
                    v2,
                    v3,
                    v4, 
                    incidenttettags,
                    &numincident,
                    &noghosts);
    assert(numincident > 0);
    
    if (improvebehave.verbosity > 5)
    {
        printf("here are the incident tets:\n");
        printtets(mesh, incidenttettags, numincident);
    }
    
    /* copy tags to incident tet data structure */
    for (incIter=0; incIter<numincident; incIter++)
    {
        /* copy vertex tags */
        incidenttets[incIter].verts[0] = incidenttettags[incIter][0];
        incidenttets[incIter].verts[1] = incidenttettags[incIter][1];
        incidenttets[incIter].verts[2] = incidenttettags[incIter][2];
        incidenttets[incIter].verts[3] = incidenttettags[incIter][3];
    }
    
    /* smooth the new vertex. */
    smoothed = nonsmooth(mesh,
                         v1,
                         incidenttets,
                         numincident,
                         worstout,
                         kinds);
    
    if (smoothed) return true;
    return false;
}

/* combination lap/opt smoothing for a single vertex
   v1, part of the existing tet (1,2,3,4) */
bool smoothsinglevertex(struct tetcomplex *mesh,
                        tag v1,
                        tag v2,
                        tag v3,
                        tag v4,
                        starreal threshold,
                        starreal *worstout,
                        int kinds,
                        int *optattempts,
                        int *optsuccesses,
                        struct arraypoolstack *outstack)
{
    int numincident = 0;
    bool noghosts = true;
    int i;
    bool optsmoothed=false;
    struct improvetet *outtet;
    starreal thisqual, startworstqual=HUGEFLOAT;
    
    /* a list of all the tets incident to this vertex */
    tag incidenttettags[MAXINCIDENTTETS][4];
    /* a list of information about all the incident tets */
    struct opttet incidenttets[MAXINCIDENTTETS];
    
    if (tetexists(mesh, v1, v2, v3, v4) == false)
    {
        return false;
    }
    
    getincidenttets(mesh, 
                    v1,
                    v2,
                    v3,
                    v4, 
                    incidenttettags,
                    &numincident,
                    &noghosts);
    assert(numincident > 0);
    
    if (improvebehave.verbosity > 5)
    {
        printf("here are the incident tets:\n");
        printtets(mesh, incidenttettags, numincident);
    }
    
    /* copy tags to incident tet data structure */
    for (i=0; i<numincident; i++)
    {
        /* copy vertex tags */
        incidenttets[i].verts[0] = incidenttettags[i][0];
        incidenttets[i].verts[1] = incidenttettags[i][1];
        incidenttets[i].verts[2] = incidenttettags[i][2];
        incidenttets[i].verts[3] = incidenttettags[i][3];
        
        /* compute starting worst quality */
        if (SMOOTHPARANOID)
        {
            thisqual = tetquality(mesh, 
                                  incidenttets[i].verts[0],
                                  incidenttets[i].verts[1],
                                  incidenttets[i].verts[2],
                                  incidenttets[i].verts[3],
                                  improvebehave.qualmeasure);
        
            /* is this the worst quality incident tet? */
            if (thisqual < startworstqual) startworstqual = thisqual;
        }
    }
    
    /* if that fails to acheive desired quality, use non-smooth optimization-based smoothing */
    if (improvebehave.nonsmooth)
    {
        (*optattempts)++;
        optsmoothed = nonsmooth(mesh,
                                v1,
                                incidenttets,
                                numincident,
                                worstout,
                                kinds);
                                
        if (optsmoothed) (*optsuccesses)++;
    }

    if (optsmoothed)
    {
        /* if we are given an output stack, add all the incident tets to it*/
        if (outstack != NULL)
        {
            for (i=0; i<numincident; i++)
            {
                /* if we don't already have this one */
                if (tetinstack(outstack,
                               incidenttettags[i][0],
                               incidenttettags[i][1],
                               incidenttettags[i][2],
                               incidenttettags[i][3]) == false)
                {
                    outtet = (struct improvetet *) stackpush(outstack);
                    outtet->verts[0] = incidenttettags[i][0];
                    outtet->verts[1] = incidenttettags[i][1];
                    outtet->verts[2] = incidenttettags[i][2];
                    outtet->verts[3] = incidenttettags[i][3];
                }
            }
        }
        return true;
    }
    return false;
}

/* perform a pass of combination Laplacian / optimization-based smoothing. */
#define SKIPCHECKSIZE 0
bool smoothpass(struct tetcomplex *mesh,
                struct arraypoolstack *tetstack,
                struct arraypoolstack *outstack,
                struct arraypoolstack *influencestack,
                int qualmeasure,
                starreal threshold,
                starreal bestmeans[],
                starreal meanqualafter[],
                starreal *minqualafter,
                int smoothkinds,
                bool quiet)
{
    struct improvetet *stacktet;   /* point to stack tet */
    struct improvetet *outtet;     /* point to stack tet */
    int origstacksize;             /* number of tets in the original stack */
    int optattempts=0;             /* number of times optimization-based is tried */
    int optsuccesses=0;            /* number of times it succeeds */
    int fixedverts[2] = {0,0};
    int facetverts[2] = {0,0};
    int segmentverts[2] = {0,0};
    int freeverts[2] = {0,0};
    starreal worstqual;
    int i,j,k,l;                   /* loop indices */
    bool smoothed;                 /* was smoothing successful? */
    int kind;                      /* number of degrees of freedom for vertex */
    int beforeid = lastjournalentry();
    starreal minqualbefore = HUGEFLOAT;
    starreal meanqualbefore[NUMMEANTHRESHOLDS];
    int nonexist = 0;
    struct vertextype *smoothedvert;
    struct arraypool smoothedverts; /* list of vertices that have already been smoothed */
    bool *thisvertsmoothed;
    bool skip = false;
    bool dynfailcondition = true;
    
    *minqualafter = HUGEFLOAT;
    
    origstacksize = tetstack->top + 1;
    
    /* reset output stack */
    if (outstack != NULL)
    {
        assert(influencestack != NULL);
        
        /* copy the input stack to output stack */
        stackrestart(outstack);
        copystack(tetstack, outstack);
    }
    
    if (improvebehave.verbosity > 5 && outstack != NULL)
    {
        printf("input stack:\n");
        printstack(mesh, tetstack);
    }
    
    /* because if we smooth each vertex of each tet, we'll smooth some vertices
       over and over again, keep track of which vertices have been smoothed */
    
    /* initialize the list */
    arraypoolinit(&smoothedverts, sizeof(bool), LOG2TETSPERSTACKBLOCK, 0);
    if (origstacksize > SKIPCHECKSIZE)
    {
        /* set initial value of "smoothed or not" for every vertex */
        initsmoothedvertlist(tetstack, &smoothedverts);
    }
    
    /* compute worst input quality. do it global if no output stack */
    if (outstack != NULL)
    {
        stackquality(mesh, tetstack, qualmeasure, meanqualbefore, &minqualbefore);
    }
    else
    {
        meshquality(mesh, qualmeasure, meanqualbefore, &minqualbefore);
    }
    
    /* try to pop all the tets off the stack */
    while (tetstack->top != STACKEMPTY)
    {
        /* pull the top tet off the stack */
        stacktet = (struct improvetet *) stackpop(tetstack);
        
        /* make sure this tet exists */
        if (tetexists(mesh, stacktet->verts[0], 
                            stacktet->verts[1], 
                            stacktet->verts[2], 
                            stacktet->verts[3]) == false)
        {
            nonexist++;
            continue;
        }
        
        if (outstack != NULL)
        {
            /* save this tet in the influenced tets stack */
            outtet = (struct improvetet *) stackpush(influencestack);
            outtet->quality = 0.0;
            outtet->verts[0] = stacktet->verts[0];
            outtet->verts[1] = stacktet->verts[1];
            outtet->verts[2] = stacktet->verts[2];
            outtet->verts[3] = stacktet->verts[3];
        }
        
        /* we're not doing simultaneous smoothing; try to smooth each vertex of this tet */
        for (i = 0; i < 4; i++) 
        {
            j = (i + 1) & 3;
            if ((i & 1) == 0) {
                l = (i + 3) & 3;
                k = (i + 2) & 3;
            } else {
                l = (i + 2) & 3;
                k = (i + 3) & 3;
            }
            
            skip = false;
            
            /* if we have not yet smoothed this vertex */
            if (origstacksize > SKIPCHECKSIZE)
            {
                thisvertsmoothed = (bool *) arraypoollookup(&smoothedverts, stacktet->verts[i]);
                assert(thisvertsmoothed != NULL);
                if (*thisvertsmoothed == true)
                {
                    if (improvebehave.verbosity > 5)
                    {
                        printf("skipping double smoothing of vertex %d\n", (int) stacktet->verts[i]);
                    }
                    skip = true;
                }
            }
            
            if (skip == false)
            {
                if (origstacksize > SKIPCHECKSIZE)
                {
                    *((bool *) arraypoolforcelookup(&smoothedverts, stacktet->verts[i])) = true;
                }
                
                /* record that we have smoothed this vertex */
                arraypoolforcelookup(&smoothedverts, stacktet->verts[i]);
                
                /* look up vertex type */
                smoothedvert = (struct vertextype *) arraypoollookup(&vertexinfo, stacktet->verts[i]);
                assert(smoothedvert != NULL);
                assert(smoothedvert->kind != INPUTVERTEX);
                kind = smoothedvert->kind;
                /* record smoothing attempt */
                switch (kind)
                {
                    case FREEVERTEX: 
                        freeverts[0]++;
                        break;
                    case FACETVERTEX:
                        facetverts[0]++;
                        break;
                    case SEGMENTVERTEX:
                        segmentverts[0]++;
                        break;
                    case FIXEDVERTEX:
                        fixedverts[0]++;
                        break;
                    default:
                        printf("bizarre vertex type %d in smooth, dying\n", kind);
                        starexit(1);
                        break;
                }
                
                /* try to smooth it */
                /* only record affected tets if we were given an output stack */
                worstqual = 1e-100;
                smoothed = smoothsinglevertex(mesh,
                                   stacktet->verts[i],
                                   stacktet->verts[j],
                                   stacktet->verts[k],
                                   stacktet->verts[l],
                                   threshold,
                                   &worstqual,
                                   smoothkinds,
                                   &optattempts,
                                   &optsuccesses,
                                   influencestack);
                
                /* record number of successful smooths for this type of vertex */
                if (smoothed)
                {
                    switch (kind)
                    {
                        case FREEVERTEX: 
                            freeverts[1]++;
                            break;
                        case FACETVERTEX:
                            facetverts[1]++;
                            break;
                        case SEGMENTVERTEX:
                            segmentverts[1]++;
                            break;
                        case FIXEDVERTEX:
                            fixedverts[1]++;
                            break;
                    }
                }
                
                if (improvebehave.verbosity > 5 && optattempts % 1000 == 0 && quiet == false && optattempts != 0)
                {
                    printf("Attempted %d smooths, stack size currently %lu\n", optattempts, tetstack->top);
                }
            }
        }
    }
    
    if (outstack != NULL)
    {
        /* check the quality of all influenced tets */
        stackquality(mesh, influencestack, qualmeasure, meanqualafter, minqualafter);
        
        if (improvebehave.verbosity > 4 && quiet == false)
        {
            printf("just finished smoothing pass.\n");
            printf("    in stack size: %d - %d nonexistent = %d\n", origstacksize, nonexist, origstacksize-nonexist);
            printf("    influence stack size: %lu\n", influencestack->top+1);
            printf("    before min qual is %g\n", pq(minqualbefore));
            printf("    after min qual is %g\n", pq(*minqualafter));
            printf("    Mean qualities before:\n");
            printmeans(meanqualbefore);
            printf("    Mean qualities after:\n");
            printmeans(meanqualafter);
        }
        
        /* check for success for local dynamic improvement */
        if (improvebehave.dynimprove && quiet == false)
        {
            if (localmeanimprove(meanqualbefore, meanqualafter, 0.001) && *minqualafter >= minqualbefore)
            {
                dynfailcondition = false;
            }
        }
        
        /* the output stack must have at least as many tets as the input stack */
        assert(influencestack->top + 1 >= origstacksize - nonexist);
        
        /* if we failed to improve the worst quality, undo this pass */
        if (*minqualafter <= minqualbefore && dynfailcondition)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("Undoing last smoothing pass, minqualbefore was %g but after was %g\n", minqualbefore, *minqualafter);
            }
            invertjournalupto(mesh, beforeid);
            
            /* reset minimum output quality */
            *minqualafter = minqualbefore;
            
            /*starreal invertworst;
            stackquality(mesh, outstack, qualmeasure, meanqualafter, &invertworst);
            
            if (invertworst != minqualbefore)
            {
                printf("after inverting journal, worst is %g, before pass it was %g\n", invertworst, minqualbefore);
            }
            
            assert(invertworst == minqualbefore); */
            
            arraypooldeinit(&smoothedverts);
            return false;
        }
    }
    
    if (quiet == false && outstack == NULL)
    {
        /* what's the worst quality element in the mesh now? */
        meshquality(mesh, qualmeasure, meanqualafter, minqualafter);
    }
    
    /* print report */
    if (improvebehave.verbosity > 3 && quiet == false)
    {
        printf("Completed pass of optimization-based smoothing on stack of %d tets.\n", origstacksize);
        if (improvebehave.verbosity > 5)
        {
            if (bestmeans != NULL)
            {
                printf("    Best previous means:\n");
                printmeans(bestmeans);
            }
            printf("    Mean qualities after:\n");
            printmeans(meanqualafter);
        }
        printf("    Worst quality before: %g\n", pq(minqualbefore));
        if (minqualbefore < *minqualafter)
        {
            textcolor(BRIGHT, GREEN, BLACK);
        }
        printf("    Worst quality after:  %g\n", pq(*minqualafter));
        textcolor(RESET, WHITE, BLACK);
        if (improvebehave.verbosity > 4)
        {
            printf("    Optimization smoothing attempts:  %d\n", optattempts);
            printf("    Optimization smoothing successes: %d\n", optsuccesses);
            printf("    Free vertices (succ/tries):       %d/%d\n", freeverts[1], freeverts[0]); 
            printf("    Facet vertices (succ/tries):      %d/%d\n", facetverts[1], facetverts[0]);
            printf("    Segment vertices (succ/tries):    %d/%d\n", segmentverts[1], segmentverts[0]);
            printf("    Fixed vertices (succ/tries):      %d/%d\n", fixedverts[1], fixedverts[0]);
        }
    }
    
    /* free list of smoothed verts */
    arraypooldeinit(&smoothedverts);
    return true;
}


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBranchUtilities.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkPolyDataBranchUtilities.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:46:43 $
Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkPolyDataBranchUtilities - Utility functions to ease working with branches and surfaces. 
// .SECTION Description
// - ExtractGroup: Extract a single surface branch group from a surface which has already been grouped. 
// - GetGroupIdsList: get the group ids which are contained within a grouped surface as a vtkIdList.

#ifndef __vtkvmtkPolyDataBranchUtilities_h
#define __vtkvmtkPolyDataBranchUtilities_h

#include "vtkObject.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"

class vtkPolyData;
class vtkIdList;

class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataBranchUtilities : public vtkObject
{
public: 
  vtkTypeMacro(vtkvmtkPolyDataBranchUtilities,vtkObject);
  static vtkvmtkPolyDataBranchUtilities* New();

  static void GetGroupsIdList(vtkPolyData* surface, const char* groupIdsArrayName, vtkIdList* groupIds);
  static void ExtractGroup(vtkPolyData* surface, const char* groupIdsArrayName, vtkIdType groupId, bool cleanGroupSurface, vtkPolyData* groupSurface);
  
protected:
  vtkvmtkPolyDataBranchUtilities() {};
  ~vtkvmtkPolyDataBranchUtilities() {};

private:
  vtkvmtkPolyDataBranchUtilities(const vtkvmtkPolyDataBranchUtilities&);  // Not implemented.
  void operator=(const vtkvmtkPolyDataBranchUtilities&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Misc/vtkvmtkStaticTemporalInterpolatedVelocityField.h<|end_filename|>
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkvmtkStaticTemporalInterpolatedVelocityField.h

  Copyright (c) <NAME>, <NAME>, <NAME>
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*=========================================================================

Program:   VMTK
Language:  C++

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkStaticTemporalInterpolatedVelocityField - A concrete class for obtaining the interpolated velocity values at a point.


#ifndef __vtkvmtkStaticTemporalInterpolatedVelocityField_h
#define __vtkvmtkStaticTemporalInterpolatedVelocityField_h

#include "vtkvmtkWin32Header.h"
#include "vtkVersion.h"

#if (VTK_MAJOR_VERSION <= 5)
#include "vtkAbstractInterpolatedVelocityField.h"
#else
#include "vtkInterpolatedVelocityField.h"
#endif

class vtkTable;
#if (VTK_MAJOR_VERSION > 5)
class vtkAbstractInterpolatedVelocityFieldDataSetsType;
#endif

class VTK_VMTK_MISC_EXPORT vtkvmtkStaticTemporalInterpolatedVelocityField
#if (VTK_MAJOR_VERSION <= 5)
  : public vtkAbstractInterpolatedVelocityField
#else
  : public vtkInterpolatedVelocityField
#endif
{
public:
#if (VTK_MAJOR_VERSION <= 5)
  vtkTypeMacro( vtkvmtkStaticTemporalInterpolatedVelocityField,
                        vtkAbstractInterpolatedVelocityField );
#else
  vtkTypeMacro( vtkvmtkStaticTemporalInterpolatedVelocityField,
                      vtkInterpolatedVelocityField );

#endif
  void PrintSelf( ostream & os, vtkIndent indent ) VTK_OVERRIDE;

  // Description:
  // Construct a vtkvmtkStaticTemporalInterpolatedVelocityField without an initial dataset.
  // Caching is set on and LastCellId is set to -1.
  static vtkvmtkStaticTemporalInterpolatedVelocityField * New();

#if (VTK_MAJOR_VERSION <= 5)
  // Description:
  // Add a dataset used for the implicit function evaluation. If more than
  // one dataset is added, the evaluation point is searched in all until a 
  // match is found. THIS FUNCTION DOES NOT CHANGE THE REFERENCE COUNT OF 
  // DATASET FOR THREAD SAFETY REASONS.
  virtual void AddDataSet( vtkDataSet * dataset );
#endif
  
  vtkGetObjectMacro(TimeStepsTable,vtkTable);
  virtual void SetTimeStepsTable(vtkTable*);

  vtkSetMacro(Periodic, int);
  vtkGetMacro(Periodic, int);
  vtkBooleanMacro(Periodic, int);

  vtkSetMacro(VelocityScale, double);
  vtkGetMacro(VelocityScale, double);

  vtkSetMacro(UseVectorComponents, int);
  vtkGetMacro(UseVectorComponents, int);
  vtkBooleanMacro(UseVectorComponents, int);

  vtkSetStringMacro(VectorPrefix);
  vtkGetStringMacro(VectorPrefix);

  vtkSetStringMacro(Component0Prefix);
  vtkGetStringMacro(Component0Prefix);

  vtkSetStringMacro(Component1Prefix);
  vtkGetStringMacro(Component1Prefix);

  vtkSetStringMacro(Component2Prefix);
  vtkGetStringMacro(Component2Prefix);

#if (VTK_MAJOR_VERSION <= 5)
  // Description:
  // Evaluate the velocity field f at point (x, y, z, t).
  virtual int FunctionValues( double * x, double * f ) VTK_OVERRIDE;
#endif
  
  // Description:
  // Set the cell id cached by the last evaluation within a specified dataset.
  virtual void SetLastCellId( vtkIdType c, int dataindex ) VTK_OVERRIDE;
  
  // Description:
  // Set the cell id cached by the last evaluation.
  virtual void SetLastCellId( vtkIdType c ) VTK_OVERRIDE
    { this->Superclass::SetLastCellId( c ); }

  virtual void CopyParameters( vtkAbstractInterpolatedVelocityField * from ) VTK_OVERRIDE;

protected:
  vtkvmtkStaticTemporalInterpolatedVelocityField();
  ~vtkvmtkStaticTemporalInterpolatedVelocityField();

  // Description:
  // Evaluate the velocity field f at point (x, y, z) in a specified dataset
  // by either involving vtkPointLocator, via vtkPointSet::FindCell(), in
  // locating the next cell (for datasets of type vtkPointSet) or simply
  // invoking vtkImageData/vtkRectilinearGrid::FindCell() to fulfill the same
  // task if the point is outside the current cell.
  virtual int FunctionValues( vtkDataSet * ds, double * x, double * f ) VTK_OVERRIDE;

  void FindTimeRowId(double time, int& prevRowId, int& nextRowId, double& p);

  void BuildArrayName(char* prefix, int index, char* name);

  vtkTable* TimeStepsTable;

  int Periodic;

  double VelocityScale;

  int UseVectorComponents;

  char* VectorPrefix;
  char* Component0Prefix;
  char* Component1Prefix;
  char* Component2Prefix;
#if (VTK_MAJOR_VERSION > 5)
  int LastDataSetIndex;
#endif

private:
  vtkvmtkStaticTemporalInterpolatedVelocityField
    ( const vtkvmtkStaticTemporalInterpolatedVelocityField & );  // Not implemented.
  void operator = 
    ( const vtkvmtkStaticTemporalInterpolatedVelocityField & );  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataPatchingFilter.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkPolyDataPatchingFilter.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:43 $
  Version:   $Revision: 1.6 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkPolyDataPatchingFilter - “cut” a set of contiguous rectangular regions on the mesh that follow iso-contours in the StretchedMapping and AngularMetric arrays over which all the quantities of interest are averaged.
// .SECTION Description
// This script is designed to help map the surface of a population of vessels onto the same parametric space in order to enable statistical analyses of surface-based quantities.
//
// By means of the options PatchSize and CircularPatching, we impose the dimensions of the patches, in terms of “height” (in mm) of the patch along the longitudinal direction and number of angular cut over the interval (-π, +π) respectively; the result of this discretization can be seen visualizing the Slab and Sector arrays created by the script or the mesh new surface discretization.

#ifndef __vtkvmtkPolyDataPatchingFilter_h
#define __vtkvmtkPolyDataPatchingFilter_h

#include "vtkPolyDataAlgorithm.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"
#include "vtkImageData.h"

class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataPatchingFilter : public vtkPolyDataAlgorithm
{
public:
  static vtkvmtkPolyDataPatchingFilter* New();
  vtkTypeMacro(vtkvmtkPolyDataPatchingFilter,vtkPolyDataAlgorithm);

  vtkSetStringMacro(LongitudinalMappingArrayName);
  vtkGetStringMacro(LongitudinalMappingArrayName);

  vtkSetStringMacro(CircularMappingArrayName);
  vtkGetStringMacro(CircularMappingArrayName);

  vtkSetStringMacro(GroupIdsArrayName);
  vtkGetStringMacro(GroupIdsArrayName);

  vtkSetStringMacro(LongitudinalPatchNumberArrayName);
  vtkGetStringMacro(LongitudinalPatchNumberArrayName);

  vtkSetStringMacro(CircularPatchNumberArrayName);
  vtkGetStringMacro(CircularPatchNumberArrayName);

  vtkSetStringMacro(PatchAreaArrayName);
  vtkGetStringMacro(PatchAreaArrayName);

  vtkSetVector2Macro(PatchSize,double);
  vtkGetVectorMacro(PatchSize,double,2);

  vtkSetVector2Macro(PatchOffsets,double);
  vtkGetVectorMacro(PatchOffsets,double,2);

  vtkSetVector2Macro(LongitudinalPatchBounds,double);
  vtkGetVectorMacro(LongitudinalPatchBounds,double,2);

  vtkSetVector2Macro(CircularPatchBounds,double);
  vtkGetVectorMacro(CircularPatchBounds,double,2);

  vtkSetObjectMacro(PatchedData,vtkImageData);
  vtkGetObjectMacro(PatchedData,vtkImageData);

  vtkSetMacro(CircularPatching,int);
  vtkGetMacro(CircularPatching,int);
  vtkBooleanMacro(CircularPatching,int);

  vtkSetMacro(UseConnectivity,int);
  vtkGetMacro(UseConnectivity,int);
  vtkBooleanMacro(UseConnectivity,int);

protected:
  vtkvmtkPolyDataPatchingFilter();
  ~vtkvmtkPolyDataPatchingFilter();

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  char* LongitudinalMappingArrayName;
  char* CircularMappingArrayName;
  char* GroupIdsArrayName;

  char* LongitudinalPatchNumberArrayName;
  char* CircularPatchNumberArrayName;

  char* PatchAreaArrayName;

  double PatchSize[2];
  double PatchOffsets[2];
  double LongitudinalPatchBounds[2];
  double CircularPatchBounds[2];

  vtkImageData* PatchedData;

  int CircularPatching;
  int UseConnectivity;

private:
  vtkvmtkPolyDataPatchingFilter(const vtkvmtkPolyDataPatchingFilter&);  // Not implemented.
  void operator=(const vtkvmtkPolyDataPatchingFilter&);  // Not implemented.
};

#endif



<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/quadric.c<|end_filename|>
/* functions related to quadric error metrics */

/* compute the quadric error for a query position of a vertex */
starreal quadricerrorquery(struct tetcomplex *mesh,
                           tag vtag,
                           starreal v[3])
{
    struct quadric *q;
    starreal quad;
    
    /* fetch the quadric for this vertex */
    q = (struct quadric *) arraypoolforcelookup(&surfacequadrics, vtag);
    assert(q != NULL);
    
    /* return zero if this is not a surface vertex */
    if (q->hasquadric == false) return 0.0;
    
    /* evaluate quadric */
    /* Q(v) = v'Av + 2b'v + c */
    quad = v[0]*v[0]*q->a2 + 2*v[0]*v[1]*q->ab + 2*v[0]*v[2]*q->ac + 2*v[0]*q->ad
                           + v[1]*v[1]*q->b2   + 2*v[1]*v[2]*q->bc + 2*v[1]*q->bd
                                               + v[2]*v[2]*q->c2   + 2*v[2]*q->cd
                                                                   + q->d2;
    
    /*                                                               
    if (quad > 1.0e-8)
    {
        printf("Encountered a large quadric error of %g\n", quad);
        printf("Quadric:\n");
        printf("    a2 = %g\n", q->a2);
        printf("    ab = %g\n", q->ab);
        printf("    ac = %g\n", q->ac);
        printf("    ad = %g\n", q->ad);
        printf("    b2 = %g\n", q->b2);
        printf("    bc = %g\n", q->bc);
        printf("    bd = %g\n", q->bd);
        printf("    c2 = %g\n", q->c2);
        printf("    cd = %g\n", q->cd);
        printf("    d2 = %g\n", q->d2);
        printf("Vertex:\n");
        printf("    x = %g\n", v[0]);
        printf("    y = %g\n", v[1]);
        printf("    z = %g\n", v[2]);
    }
    assert(quad < 1.0e-8);
    */
                                                                   
    return quad;
}

/* compute the quadric error for a particular vertex's current position */
starreal quadricerror(struct tetcomplex *mesh,
                      tag vtag)
{
    /* fetch this vertex's current position */
    starreal *v = ((struct vertex *) tetcomplextag2vertex(mesh, vtag))->coord;
    
    return quadricerrorquery(mesh, vtag, v);
}

/* compute the quadric error at a vertex, normalized to
   be comparable to tetrahedron quality measures */
starreal quadricerrortet(struct tetcomplex *mesh,
                         tag vtag)
{
    /* return the quadric error of this vertex scaled
       by the quadric scale and offset by the quadric offset */
    starreal qe = improvebehave.quadricoffset - 
                  (improvebehave.quadricscale * quadricerror(mesh, vtag));
    
    /* scale down so that perfect corresponds to equilateral */
    if (improvebehave.qualmeasure == QUALMINSINE ||
        improvebehave.qualmeasure == QUALWARPEDMINSINE)
    {
        qe *= SINEEQUILATERAL;
    }
    
    /* don't return negative qualities */
    if (qe < 0.0) return 0.0;
    return qe;
}

bool hasquadric(tag vtag)
{
    struct quadric *q = (struct quadric *) arraypoolforcelookup(&surfacequadrics, vtag);
    assert(q != NULL);
    return q->hasquadric;
}

/* compute the gradient of the quadric error for query point */
void quadricgradquery(struct tetcomplex *mesh,
                      tag vtag,
                      starreal v[3],
                      starreal grad[3])
{
    struct quadric *q;
    
    /* fetch the quadric for this vertex */
    q = (struct quadric *) arraypoolforcelookup(&surfacequadrics, vtag);
    assert(q != NULL);
    
    /* return a zero gradient if this is not a surface vertex */
    if (q->hasquadric == false)
    {
        grad[0] = grad[1] = grad[2] = 0.0;
        return;
    }
    
    /* grad(Q) = 2Av + 2b */
    /* A = nn', b = dn */
    /* so */
    /* grad(Q) = 2 [xa2 + yab + zac + ad] */
    /*             [xab + yb2 + zbc + bd] */
    /*             [xac + ybc + zc2 + cd] */
    /* negative because we want to *reduce* quadric error... */
    grad[0] = -2.0 * (v[0]*q->a2 + v[1]*q->ab + v[2]*q->ac + q->ad);
    grad[1] = -2.0 * (v[0]*q->ab + v[1]*q->b2 + v[2]*q->bc + q->bd);
    grad[2] = -2.0 * (v[0]*q->ac + v[1]*q->bc + v[2]*q->c2 + q->cd);
    
    /* scale gradient by quadric scale factor */
    /*
    grad[0] *= improvebehave.quadricscale;
    grad[1] *= improvebehave.quadricscale;
    grad[2] *= improvebehave.quadricscale;
    */
    return;
}

/* compute the gradient of the quadric error for a vertex */
void quadricgrad(struct tetcomplex *mesh,
                 tag vtag,
                 starreal grad[3])
{
    starreal *v;
    
    /* fetch this vertex's position */
    v = ((struct vertex *) tetcomplextag2vertex(mesh, vtag))->coord;
    
    /* compute the gradient for the vertex's current position */
    quadricgradquery(mesh, vtag, v, grad);
    
    return;
}

/* compute the gradient of the quadric error, scaled for tet comparison */
void quadricgradtet(struct tetcomplex* mesh,
                    tag vtag,
                    starreal grad[3])
{
    quadricgrad(mesh, vtag, grad);
    
    /* vscale(improvebehave.quadricscale, grad, grad); */
}

/* add a quadric for a newly inserted vertex */
bool addquadric(struct tetcomplex *mesh,
                tag vtag,
                tag faces[][3],
                int numfaces)
{
    int i,j;
    proxipool *pool = mesh->vertexpool;
    struct vertex *newv, *vptr[3];
    struct quadric *vquads[3];
    starreal e1[3], e2[3], normal[3];
    starreal facearea, d, normfactor;
    /* create quadric */
    struct quadric *q = (struct quadric *) arraypoolforcelookup(&surfacequadrics, vtag);
    
    /* initialize quadric */
    q->hasquadric = true;
    
    q->a2 = q->ab = q->ac = q->ad 
          = q->b2 = q->bc = q->bd 
                  = q->c2 = q->cd 
                          = q->d2 = 0.0;
    
    q->numfaces = 0;
    q->facesum = 0.0;
    q->edge2harm = 0.0;
    
    newv = (struct vertex *) proxipooltag2object(pool, vtag);
    vcopy(newv->coord, q->origpos);
    
    /* accumulate fundamental quadric for each incident face */
    for (i=0; i<numfaces; i++)
    {
        /* get the actual vertices */
        vptr[0] = (struct vertex *) proxipooltag2object(pool, faces[i][0]);
        vptr[1] = (struct vertex *) proxipooltag2object(pool, faces[i][1]);
        vptr[2] = (struct vertex *) proxipooltag2object(pool, faces[i][2]);
        
        /* get original vertex positions */
        vquads[0] = (struct quadric *) arraypoolforcelookup(&surfacequadrics, faces[i][0]);
        vquads[1] = (struct quadric *) arraypoolforcelookup(&surfacequadrics, faces[i][1]);
        vquads[2] = (struct quadric *) arraypoolforcelookup(&surfacequadrics, faces[i][2]);
        
        /* compute face normal */
        /*
        vsub(vptr[1]->coord, vptr[0]->coord, e1);
        vsub(vptr[2]->coord, vptr[0]->coord, e2);
        */
        vsub(vquads[1]->origpos, vquads[0]->origpos, e1);
        vsub(vquads[2]->origpos, vquads[0]->origpos, e2);
        cross(e1, e2, normal);
        
        /* face area is 1/2 the length of the cross product */
        facearea = vlength(normal) / 2.0;
        if (facearea < 1.e-14 && 0)
        {
            printf("In addquadric, face (%d %d %d) has odd area %g.\n", (int) faces[i][0], (int) faces[i][1], (int) faces[i][2], facearea);
            for (j=0; j<3; j++)
            {
                printf("    %d = (%g %g %g)\n", j, vquads[j]->origpos[0], vquads[j]->origpos[1], vquads[j]->origpos[2]);
            }
        }
        
        /* normalize the normal */
        vscale(1.0 / (facearea * 2.0), normal, normal);
        
        /* compute the orthogonal distance from the plane of this face to
           the origin */
        d = -dot(normal, vptr[0]->coord);
        
        q->numfaces++;
        q->facesum += facearea;
        /* add on 1/2 of 1 / l^2, because every edge will be counted twice */
        if (vlength(e1) > 0.0 && vlength(e2) > 0.0)
        {
            q->edge2harm += (0.5 / (vlength(e1) * vlength(e1)));
            q->edge2harm += (0.5 / (vlength(e2) * vlength(e2)));
        }
        
        /* accumulate the fundamental quadric from this face */
        /* normal = [a b c] */
        q->a2 += normal[0] * normal[0] * facearea;
        q->ab += normal[0] * normal[1] * facearea;
        q->ac += normal[0] * normal[2] * facearea;
        q->ad += normal[0] * d * facearea;
        q->b2 += normal[1] * normal[1] * facearea;
        q->bc += normal[1] * normal[2] * facearea;
        q->bd += normal[1] * d * facearea;
        q->c2 += normal[2] * normal[2] * facearea;
        q->cd += normal[2] * d * facearea;
        q->d2 += d * d * facearea;
    }
    
    /* compute normalization */
    /* quadric must have at least 3 surrounding faces */
    assert(q->numfaces >= 3);
    
    /* compute harmonic mean */
    q->edge2harm = ((starreal) q->numfaces) / q->edge2harm;
    
    /* compute normalization factor */
    normfactor = q->edge2harm * q->facesum;
    
    /* if the facesum is zero, bail */
    if (q->facesum <= 0.0)
    {
        return false;
    }
    
    assert(q->edge2harm != 0.0);
    assert(q->facesum != 0.0);
    assert(normfactor != 0.0);
    
    /* scale quadric by normalization factor */
    q->a2 /= normfactor;
    q->ab /= normfactor;
    q->ac /= normfactor;
    q->ad /= normfactor;
    q->b2 /= normfactor;
    q->bc /= normfactor;
    q->bd /= normfactor;
    q->c2 /= normfactor;
    q->cd /= normfactor;
    q->d2 /= normfactor;
    
    return true;
}

/* normalize quadric by dividing by the sum of the face areas
   and the harmonic mean of the edge lengths squared */
void normalizequadrics(struct tetcomplex *mesh)
{
    struct quadric *q;
    tag vertextag;
    starreal normfactor; /* normalization factor */
    
    /* check each quadric */
    proxipool *pool = mesh->vertexpool;
    vertextag = proxipooliterate(pool, NOTATAG);
    while (vertextag != NOTATAG)
    {
        /* get the quadric for this vertex */
        q = (struct quadric *) arraypoolforcelookup(&surfacequadrics, vertextag);
        assert(q != NULL);
        
        /* if this isn't a surface vertex, move on */
        if (q->hasquadric == false)
        {
            /* move to next vertex */
            vertextag = proxipooliterate(pool, vertextag);
            continue;
        }
        
        /* normalize this vertex's quadric */
        if (improvebehave.verbosity > 5)
        {
            printf("Normalizing quadric for vertex %d\n", (int) vertextag);
            printf("    Quadric has %d incident faces\n", q->numfaces);
        }
        /* quadric must have at least 3 surrounding faces */
        assert(q->numfaces >= 3);
        
        /* compute harmonic mean */
        q->edge2harm = ((starreal) q->numfaces) / q->edge2harm;
        
        /* compute normalization factor */
        normfactor = q->edge2harm * q->facesum;
        
        if (improvebehave.verbosity > 5)
        {
            printf("    Edge length harmonic mean is %g\n", q->edge2harm);
            printf("    Face area sum is %g\n", q->facesum);
            printf("    Norm factor is %g\n", normfactor);
            printf("Quadric:\n");
            printf("    a2 = %g\n", q->a2);
            printf("    ab = %g\n", q->ab);
            printf("    ac = %g\n", q->ac);
            printf("    ad = %g\n", q->ad);
            printf("    b2 = %g\n", q->b2);
            printf("    bc = %g\n", q->bc);
            printf("    bd = %g\n", q->bd);
            printf("    c2 = %g\n", q->c2);
            printf("    cd = %g\n", q->cd);
            printf("    d2 = %g\n", q->d2);
        }
        
        assert(normfactor != 0.0);
        
        /* scale quadric by normalization factor */
        q->a2 /= normfactor;
        q->ab /= normfactor;
        q->ac /= normfactor;
        q->ad /= normfactor;
        q->b2 /= normfactor;
        q->bc /= normfactor;
        q->bd /= normfactor;
        q->c2 /= normfactor;
        q->cd /= normfactor;
        q->d2 /= normfactor;
        
        vertextag = proxipooliterate(pool, vertextag);
    }
}

/* create quadrics for all surface vertices */ 
void collectquadrics(tetcomplex *mesh)
{
    struct arraypool facepool;
    int numfaces = 0;
    int i,j;
    struct vertex *vptr[3];
    tag vertextag;
    tag *face;
    starreal normal[3], e1[3], e2[3], facearea, d;
    struct quadric *q;
    proxipool *pool = mesh->vertexpool;
    
    /* initialize the arraypool that stores the quadrics */
    arraypoolinit(&surfacequadrics, sizeof(struct quadric), LOG2TETSPERSTACKBLOCK, 0);
    
    /* allocate pool for faces */
    arraypoolinit(&(facepool), sizeof(tag)*3, LOG2TETSPERSTACKBLOCK, 0);
    /* find the surface faces */
    getsurface(mesh, &facepool, &numfaces);
    
    /* initialize all vertices to have no quadric */
    vertextag = proxipooliterate(pool, NOTATAG);
    while (vertextag != NOTATAG)
    {
        /* initialize this vertex to have no quadric */
        ((struct quadric *) arraypoolforcelookup(&surfacequadrics, vertextag))->hasquadric = false;
        
        /* move to next vertex */
        vertextag = proxipooliterate(pool, vertextag);
    }
    
    /* accumulate quadrics from each face to their vertices */
    for (i=0; i<numfaces; i++)
    {
        /* fetch this face from the pool */
        face = (tag *) arraypoolfastlookup(&facepool, (unsigned long) i);
        
        /* get the actual vertices */
        vptr[0] = (struct vertex *) proxipooltag2object(pool, face[0]);
        vptr[1] = (struct vertex *) proxipooltag2object(pool, face[1]);
        vptr[2] = (struct vertex *) proxipooltag2object(pool, face[2]);
        
        assert(vptr[0] != NULL);
        assert(vptr[1] != NULL);
        assert(vptr[2] != NULL);
        
        /*
        printf("here are the vertex positions at the start\n");
        printf("vptr[0]->coord is %p, vptr[0]->coord is (%g %g %g)\n", vptr[0]->coord, vptr[0]->coord[0], vptr[0]->coord[1], vptr[0]->coord[2]);
        printf("vptr[1]->coord is %p, vptr[1]->coord is (%g %g %g)\n", vptr[1]->coord, vptr[1]->coord[0], vptr[1]->coord[1], vptr[1]->coord[2]);
        printf("vptr[2]->coord is %p, vptr[2]->coord is (%g %g %g)\n", vptr[2]->coord, vptr[2]->coord[0], vptr[2]->coord[1], vptr[1]->coord[2]);
        printf("vptr is %p\n", vptr[0]);
        */
        
        /* compute face normal */
        vsub(vptr[1]->coord, vptr[0]->coord, e1);
        vsub(vptr[2]->coord, vptr[0]->coord, e2);
        cross(e1, e2, normal);
        
        /* face area is 1/2 the length of the cross product */
        facearea = vlength(normal) / 2.0;
        
        /* normalize the normal */
        vscale(1.0 / (facearea * 2.0), normal, normal);
        
        /* compute the orthogonal distance from the plane of this face to
           the origin */
        d = -dot(normal, vptr[0]->coord);
        
        /* accumulate the quadric at each of the face's vertices */
        for (j=0; j<3; j++)
        {
            /* fetch the quadric */
            q = (struct quadric *) arraypoolforcelookup(&surfacequadrics, face[j]);
            assert(q != NULL);
            
            /* if it is not set, initialize it */
            if (q->hasquadric == false)
            {
                q->hasquadric = true;
                
                q->a2 = q->ab = q->ac = q->ad 
                      = q->b2 = q->bc = q->bd 
                              = q->c2 = q->cd 
                                      = q->d2 = 0.0;
                
                q->numfaces = 0;
                q->facesum = 0.0;
                q->edge2harm = 0.0;
                
                q->origpos[0] = vptr[j]->coord[0];
                q->origpos[1] = vptr[j]->coord[1];
                q->origpos[2] = vptr[j]->coord[2];
                
                /*
                vcopy(vptr[j]->coord, q->origpos);
                */
            } 
            
            q->numfaces++;
            q->facesum += facearea;
            /* add on 1/2 of 1 / l^2, because every edge will be counted twice */
            q->edge2harm += (0.5 / (vlength(e1) * vlength(e1)));
            q->edge2harm += (0.5 / (vlength(e2) * vlength(e2)));
            
            /* accumulate the fundamental quadric from this face */
            /* normal = [a b c] */
            q->a2 += normal[0] * normal[0] * facearea;
            q->ab += normal[0] * normal[1] * facearea;
            q->ac += normal[0] * normal[2] * facearea;
            q->ad += normal[0] * d * facearea;
            q->b2 += normal[1] * normal[1] * facearea;
            q->bc += normal[1] * normal[2] * facearea;
            q->bd += normal[1] * d * facearea;
            q->c2 += normal[2] * normal[2] * facearea;
            q->cd += normal[2] * d * facearea;
            q->d2 += d * d * facearea;
        } 
    }
    
    /* now, go through quadrics again to normalize them */
    normalizequadrics(mesh);
}

/* do a bunch of checks on quadrics */
void checkquadricsstream(FILE *o, tetcomplex *mesh)
{
    tag vertextag;
    starreal avgquad = 0.0;
    starreal minquad = HUGEFLOAT;
    starreal maxquad = 0.0;
    starreal thisquad;
    starreal avggrad = 0.0;
    starreal mingrad = HUGEFLOAT;
    starreal maxgrad = 0.0;
    starreal thisdot;
    starreal avgdot = 0.0;
    starreal maxdot = 0.0;
    starreal mindot = HUGEFLOAT;
    starreal thisgrad;
    starreal offset[] = {-10.0, -10.0, -10.0};
    starreal correctgrad[] = {1.0, 1.0, 1.0};
    starreal testpos[3];
    starreal grad[3];
    starreal normgrad[3];
    struct quadric *q;
    int numquads = 0;
    
    /* check each quadric */
    proxipool *pool = mesh->vertexpool;
    vertextag = proxipooliterate(pool, NOTATAG);
    while (vertextag != NOTATAG)
    {
        /* get the quadric error for this vertex */
        thisquad = quadricerror(mesh, vertextag);
        quadricgrad(mesh, vertextag, grad);
        thisgrad = vlength(grad);
        
        q = (struct quadric *) arraypoolforcelookup(&surfacequadrics, vertextag);
        assert(q != NULL);
        
        if (q->hasquadric == false)
        {
            /* move to next vertex */
            vertextag = proxipooliterate(pool, vertextag);
            
            continue;
        }
        
        /* offset the vertex to a new position */
        vadd(q->origpos, offset, testpos);
        /* compute the gradient for this new position */
        quadricgradquery(mesh, vertextag, testpos, grad);
        vscale(1.0 / vlength(grad), grad, normgrad);
        /* compute the dot product of this with the expected grad */
        thisdot = dot(correctgrad, normgrad);
        
        
        /*
        if (vertextag < 100)
        {
            printf("Testing quadric gradient for vertex %d.\n", (int) vertextag);
            printf("    Original position is (%g %g %g)\n", q->origpos[0], q->origpos[1], q->origpos[2]);
            printf("    The offset position is (%g %g %g)\n", testpos[0], testpos[1], testpos[2]);
            printf("    The gradient is (%g %g %g)\n", grad[0], grad[1], grad[2]);
            printf("    The normalized gradient is (%g %g %g)\n", normgrad[0], normgrad[1], normgrad[2]);
        }
        */
        
        /* accumulate statistics */
        if (thisquad != 0.0)
        {
            avgquad += thisquad;
            avggrad += thisgrad;
            avgdot += thisdot;
            numquads++;
        }
        
        if (thisquad > maxquad) maxquad = thisquad;
        if (thisquad < minquad) minquad = thisquad;
        if (thisgrad > maxgrad) maxgrad = thisgrad;
        if (thisgrad < mingrad) mingrad = thisgrad;
        if (thisdot > maxdot) maxdot = thisdot;
        if (thisdot < mindot) mindot = thisdot;
        
        
        /* move to next vertex */
        vertextag = proxipooliterate(pool, vertextag);
    }
    
    avgquad /= (starreal) numquads;
    avggrad /= (starreal) numquads;
    avgdot /= (starreal) numquads;
    
    fprintf(o, "Quadriccheck:\n");
    fprintf(o, "    Average quadric error: %g\n", avgquad);
    fprintf(o, "    Number non-zero:       %d\n", numquads);
    fprintf(o, "    Minimum quadric error: %g\n", minquad);
    fprintf(o, "    Maximum quadric error: %g\n", maxquad);
    fprintf(o, "    Average gradient mag:  %g\n", avggrad);
    fprintf(o, "    Minimum gradient mag:  %g\n", mingrad);
    fprintf(o, "    Maximum gradient mag:  %g\n", maxgrad);
    fprintf(o, "    Average dot mag:       %g\n", avgdot);
    fprintf(o, "    Minimum dot mag:       %g\n", mindot);
    fprintf(o, "    Maximum dot mag:       %g\n", maxdot);
}

void checkquadrics(tetcomplex *mesh)
{
    checkquadricsstream(stdout, mesh);
}


<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkFEAssembler.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkFEAssembler.cxx,v $
  Language:  C++
  Date:      $Date: 2005/11/15 17:39:25 $
  Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkFEAssembler.h"
#include "vtkvmtkGaussQuadrature.h"
#include "vtkvmtkFEShapeFunctions.h"
#include "vtkObjectFactory.h"



vtkvmtkFEAssembler::vtkvmtkFEAssembler()
{
  this->DataSet = NULL;
  this->Matrix = NULL;
  this->RHSVector = NULL;
  this->SolutionVector = NULL;
  this->NumberOfVariables = 1;
  this->QuadratureOrder = 1;
}

vtkvmtkFEAssembler::~vtkvmtkFEAssembler()
{
  if (this->DataSet)
    {
    this->DataSet->Delete();
    this->DataSet = NULL;
    }
  if (this->Matrix)
    {
    this->Matrix->Delete();
    this->Matrix = NULL;
    }
  if (this->RHSVector)
    {
    this->RHSVector->Delete();
    this->RHSVector = NULL;
    }
  if (this->SolutionVector)
    {
    this->SolutionVector->Delete();
    this->SolutionVector = NULL;
    }
}

void vtkvmtkFEAssembler::Initialize(int numberOfVariables)
{
  this->NumberOfVariables = numberOfVariables;

  this->Matrix->AllocateRowsFromDataSet(this->DataSet,this->NumberOfVariables);

  this->RHSVector->Allocate(this->DataSet->GetNumberOfPoints(),this->NumberOfVariables);
  this->RHSVector->Fill(0.0);

  this->SolutionVector->Allocate(this->DataSet->GetNumberOfPoints(),this->NumberOfVariables);
  this->SolutionVector->Fill(0.0);
}

void vtkvmtkFEAssembler::DeepCopy(vtkvmtkFEAssembler *src)
{
  this->DataSet->DeepCopy(src->DataSet);
  this->Matrix->DeepCopy(src->Matrix);
  this->RHSVector->DeepCopy(src->RHSVector);
  this->SolutionVector->DeepCopy(src->SolutionVector);
  this->NumberOfVariables = src->NumberOfVariables;
  this->QuadratureOrder = src->QuadratureOrder;
}
 
void vtkvmtkFEAssembler::ShallowCopy(vtkvmtkFEAssembler *src)
{
  this->DataSet = src->DataSet;
  this->DataSet->Register(this);
  this->Matrix = src->Matrix;
  this->Matrix->Register(this);
  this->RHSVector = src->RHSVector;
  this->RHSVector->Register(this);
  this->SolutionVector = src->SolutionVector;
  this->SolutionVector->Register(this);
  this->NumberOfVariables = src->NumberOfVariables;
  this->QuadratureOrder = src->QuadratureOrder;
}



<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataAreaWeightedUmbrellaStencil.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkPolyDataAreaWeightedUmbrellaStencil.cxx,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:44 $
  Version:   $Revision: 1.2 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataAreaWeightedUmbrellaStencil.h"
#include "vtkvmtkMath.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkPolyDataAreaWeightedUmbrellaStencil);

vtkvmtkPolyDataAreaWeightedUmbrellaStencil::vtkvmtkPolyDataAreaWeightedUmbrellaStencil()
{
  this->UseExtendedNeighborhood = 0;
}

void vtkvmtkPolyDataAreaWeightedUmbrellaStencil::Build()
{
  this->Superclass::Build();

  for (vtkIdType i=0; i<this->NPoints; i++)
    {
    this->Weights[i] = 1.0/double(this->NPoints);
    }

  vtkPolyData* pdata = vtkPolyData::SafeDownCast(this->DataSet);

  int j;
  for (j=0; j<this->NPoints; j++)
    {
    this->Weights[j] = 0.0;
    }
  
  double point[3], point1[3], point2[3];
//  double vector[3], vector1[3], vector2[3];
//  double dot = 0.0;
  
  pdata->GetPoint(this->DataSetPointId,point);

//  for (j=0; j<this->NPoints; j++)
//    {
//    pdata->GetPoint(this->PointIds[j],point1);
//    pdata->GetPoint(this->PointIds[(j+1)%this->NPoints],point2);
//    vector[0] = point2[0] - point1[0];
//    vector[1] = point2[1] - point1[1];
//    vector[2] = point2[2] - point1[2];
//    vector1[0] = point1[0] - point[0];
//    vector1[1] = point1[1] - point[1];
//    vector1[2] = point1[2] - point[2];
//    vector2[0] = point2[0] - point[0];
//    vector2[1] = point2[1] - point[1];
//    vector2[2] = point2[2] - point[2];
//    vtkMath::Normalize(vector);
//    vtkMath::Normalize(vector1);
//    vtkMath::Normalize(vector2);
//    dot = vtkMath::Dot(vector,vector1);
//    this->Weights[j] += vtkMath::Distance2BetweenPoints(point,point1) * dot * sqrt(1.0 - dot*dot) / 2.0;
//    if (!(this->IsBoundary || j==this->NPoints-1))
//      {
//      dot = vtkMath::Dot(vector,vector2);
//      this->Weights[(j+1)%this->NPoints] += vtkMath::Distance2BetweenPoints(point,point2) * dot * sqrt(1.0 - dot*dot) / 2.0;
//      }
  for (j=0; j<this->NPoints; j++)
    {
    pdata->GetPoint(this->PointIds[j],point1);
    pdata->GetPoint(this->PointIds[(j+1)%this->NPoints],point2);
    double area = vtkvmtkMath::TriangleArea(point,point1,point2);
    if (!(this->IsBoundary || j==this->NPoints-1))
      {
      this->Weights[j] += area;
      this->Weights[(j+1)%this->NPoints] += area;
      }
    }
 
  this->CenterWeight[0] = 0.0;
  for (j=0; j<this->NPoints; j++)
    {
    this->CenterWeight[0] += this->Weights[j];
    }

  this->Area = this->CenterWeight[0];

  this->ScaleWithArea();

  this->ChangeWeightSign();
}

void vtkvmtkPolyDataAreaWeightedUmbrellaStencil::ScaleWithArea()
{
  this->ScaleWithAreaFactor(1.0);
}


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineReferenceSystemAttributesOffset.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkCenterlineReferenceSystemAttributesOffset.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:46:43 $
Version:   $Revision: 1.8 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkCenterlineReferenceSystemAttributesOffset.h"
#include "vtkPointData.h"
#include "vtkCellData.h"
#include "vtkIdList.h"
#include "vtkCell.h"
#include "vtkDoubleArray.h"
#include "vtkTransform.h"
#include "vtkvmtkPolyBallLine.h"
#include "vtkvmtkMath.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkCenterlineUtilities.h"
#include "vtkvmtkReferenceSystemUtilities.h"


vtkStandardNewMacro(vtkvmtkCenterlineReferenceSystemAttributesOffset);

vtkvmtkCenterlineReferenceSystemAttributesOffset::vtkvmtkCenterlineReferenceSystemAttributesOffset()
{
  this->OffsetAbscissasArrayName = NULL;
  this->OffsetNormalsArrayName = NULL;

  this->AbscissasArrayName = NULL;
  this->NormalsArrayName = NULL;
  this->GroupIdsArrayName = NULL;
  this->CenterlineIdsArrayName = NULL;

  this->ReferenceSystems = NULL;

  this->ReferenceSystemsNormalArrayName = NULL;
  this->ReferenceSystemsGroupIdsArrayName = NULL;

  this->ReferenceGroupId = 0;
}

vtkvmtkCenterlineReferenceSystemAttributesOffset::~vtkvmtkCenterlineReferenceSystemAttributesOffset()
{
  if (this->OffsetAbscissasArrayName)
    {
    delete[] this->OffsetAbscissasArrayName;
    this->OffsetAbscissasArrayName = NULL;
    }

  if (this->OffsetNormalsArrayName)
    {
    delete[] this->OffsetNormalsArrayName;
    this->OffsetNormalsArrayName = NULL;
    }

  if (this->AbscissasArrayName)
    {
    delete[] this->AbscissasArrayName;
    this->AbscissasArrayName = NULL;
    }

  if (this->NormalsArrayName)
    {
    delete[] this->NormalsArrayName;
    this->NormalsArrayName = NULL;
    }

  if (this->GroupIdsArrayName)
    {
    delete[] this->GroupIdsArrayName;
    this->GroupIdsArrayName = NULL;
    }

  if (this->CenterlineIdsArrayName)
    {
    delete[] this->CenterlineIdsArrayName;
    this->CenterlineIdsArrayName = NULL;
    }

  if (this->NormalsArrayName)
    {
    delete[] this->NormalsArrayName;
    this->NormalsArrayName = NULL;
    }

  if (this->ReferenceSystems)
    {
    this->ReferenceSystems->Delete();
    this->ReferenceSystems = NULL;
    }

  if (this->ReferenceSystemsNormalArrayName)
    {
    delete[] this->ReferenceSystemsNormalArrayName;
    this->ReferenceSystemsNormalArrayName = NULL;
    }

  if (this->ReferenceSystemsGroupIdsArrayName)
    {
    delete[] this->ReferenceSystemsGroupIdsArrayName;
    this->ReferenceSystemsGroupIdsArrayName = NULL;
    }
}

int vtkvmtkCenterlineReferenceSystemAttributesOffset::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (!this->OffsetAbscissasArrayName)
    {
    vtkErrorMacro(<<"OffsetAbscissasArrayName not specified");
    return 1;
    }

  if (!this->OffsetNormalsArrayName)
    {
    vtkErrorMacro(<<"OffsetNormalsArrayName not specified");
    return 1;
    }

  if (!this->AbscissasArrayName)
    {
    vtkErrorMacro(<<"AbscissasArrayName not specified");
    return 1;
    }

  vtkDataArray* abscissasArray = input->GetPointData()->GetArray(this->AbscissasArrayName);

  if (!abscissasArray)
    {
    vtkErrorMacro(<<"AbscissasArray with name specified does not exist");
    return 1;
    }

  if (!this->NormalsArrayName)
    {
    vtkErrorMacro(<<"NormalsArrayName not specified");
    return 1;
    }

  vtkDataArray* normalsArray = input->GetPointData()->GetArray(this->NormalsArrayName);

  if (!normalsArray)
    {
    vtkErrorMacro(<<"NormalsArray with name specified does not exist");
    return 1;
    }

  if (!this->GroupIdsArrayName)
    {
    vtkErrorMacro(<<"GroupIdsArrayName not specified");
    return 1;
    }

  vtkDataArray* groupIdsArray = input->GetCellData()->GetArray(this->GroupIdsArrayName);

  if (!groupIdsArray)
    {
    vtkErrorMacro(<<"GroupIdsArray with name specified does not exist");
    return 1;
    }

  if (!this->CenterlineIdsArrayName)
    {
    vtkErrorMacro(<<"CenterlineIdsArrayName not specified");
    return 1;
    }

  vtkDataArray* centerlineIdsArray = input->GetCellData()->GetArray(this->CenterlineIdsArrayName);

  if (!centerlineIdsArray)
    {
    vtkErrorMacro(<<"CenterlineIdsArray with name specified does not exist");
    return 1;
    }

  if (!this->ReferenceSystems)
    {
    vtkErrorMacro(<<"ReferenceSystems not specified");
    return 1;
    }

  if (this->ReferenceSystems->GetNumberOfPoints() == 0)
    {
    vtkErrorMacro(<<"ReferenceSystems empty");
    return 1;
    }
  
  if (!this->ReferenceSystemsNormalArrayName)
    {
    vtkErrorMacro(<<"ReferenceSystemsNormalArrayName not specified");
    return 1;
    }

  vtkDataArray* referenceSystemsNormalArray = this->ReferenceSystems->GetPointData()->GetArray(this->ReferenceSystemsNormalArrayName);

  if (!referenceSystemsNormalArray)
    {
    vtkErrorMacro(<<"ReferenceSystemNormalsArray with name specified does not exist");
    return 1;
    }

  if (!this->ReferenceSystemsGroupIdsArrayName)
    {
    vtkErrorMacro(<<"ReferenceSystemsGroupIdsArrayName not specified");
    return 1;
    }

  vtkDataArray* referenceSystemsGroupIdsArray = this->ReferenceSystems->GetPointData()->GetArray(this->ReferenceSystemsGroupIdsArrayName);

  if (!referenceSystemsGroupIdsArray)
    {
    vtkErrorMacro(<<"ReferenceSystemsGroupIdsArray with name specified does not exist");
    return 1;
    }

  output->DeepCopy(input);

  vtkDoubleArray* offsetAbscissasArray = vtkDoubleArray::New();
  offsetAbscissasArray->SetName(this->OffsetAbscissasArrayName);
  offsetAbscissasArray->SetNumberOfComponents(1);
  offsetAbscissasArray->SetNumberOfTuples(input->GetNumberOfPoints());

  vtkDoubleArray* offsetNormalsArray = vtkDoubleArray::New();
  offsetNormalsArray->SetName(this->OffsetNormalsArrayName);
  offsetNormalsArray->SetNumberOfComponents(3);
  offsetNormalsArray->SetNumberOfTuples(input->GetNumberOfPoints());

  // For each branch in the reference group, compute nearest point. Get abscissa and normal at that point.
  // Compute abscissa offset and normal offset rotation. 
  // Apply abscissa offset and normal offset rotation to each branch in the centerline.
 
  vtkvmtkPolyBallLine* tube = vtkvmtkPolyBallLine::New();
  tube->SetInput(input);
  tube->UseRadiusInformationOff();

  vtkIdList* tubeInputCellIds = vtkIdList::New();

  double referenceSystemOrigin[3], referenceSystemNormal[3];

  if (this->ReferenceGroupId == -1)
    {
    this->ReferenceGroupId = static_cast<int>(referenceSystemsGroupIdsArray->GetComponent(0,0));
    }
  
  int referenceSystemPointId = vtkvmtkReferenceSystemUtilities::GetReferenceSystemPointId(this->ReferenceSystems,this->ReferenceSystemsGroupIdsArrayName,this->ReferenceGroupId);

  if (referenceSystemPointId == -1)
    {
    vtkErrorMacro(<<"Invalid ReferenceGroupId");
    return 1;
    }

  this->ReferenceSystems->GetPoint(referenceSystemPointId,referenceSystemOrigin);
  referenceSystemsNormalArray->GetTuple(referenceSystemPointId,referenceSystemNormal);

  vtkIdList* groupCellIds = vtkIdList::New();
  vtkvmtkCenterlineUtilities::GetGroupCellIds(input,this->GroupIdsArrayName,this->ReferenceGroupId,groupCellIds);
  for (int i=0; i<groupCellIds->GetNumberOfIds(); i++)
    {
    vtkIdType currentCellId = groupCellIds->GetId(i);
 
    vtkIdType centerlineId = static_cast<int>(centerlineIdsArray->GetComponent(currentCellId,0));
    tubeInputCellIds->Initialize();
    tubeInputCellIds->InsertNextId(currentCellId);
    tube->SetInputCellIds(tubeInputCellIds);
        
    tube->EvaluateFunction(referenceSystemOrigin);
    
    vtkIdType cellId = tube->GetLastPolyBallCellId();
    vtkIdType subId = tube->GetLastPolyBallCellSubId();
    double pcoord = tube->GetLastPolyBallCellPCoord();

    double abscissa = 0.0;
    vtkvmtkCenterlineUtilities::InterpolateTuple1(input,this->AbscissasArrayName,cellId,subId,pcoord,abscissa);
    double abscissaOffset = - abscissa;
    
    double normal[3];
    vtkvmtkCenterlineUtilities::InterpolateTuple3(input,this->NormalsArrayName,cellId,subId,pcoord,normal);
    vtkMath::Normalize(normal);
    
    double point0[3], point1[3], tangent[3];
    input->GetCell(cellId)->GetPoints()->GetPoint(subId,point0);
    input->GetCell(cellId)->GetPoints()->GetPoint(subId+1,point1);
    tangent[0] = point1[0] - point0[0];
    tangent[1] = point1[1] - point0[1];
    tangent[2] = point1[2] - point0[2];
    double normalDot = vtkMath::Dot(tangent,normal);
    tangent[0] -= normalDot * normal[0];
    tangent[1] -= normalDot * normal[1];
    tangent[2] -= normalDot * normal[2];
    vtkMath::Normalize(tangent);
    
    double dot = vtkMath::Dot(tangent,referenceSystemNormal);
    double projectedReferenceSystemNormal[3];
    projectedReferenceSystemNormal[0] = referenceSystemNormal[0] - dot * tangent[0];
    projectedReferenceSystemNormal[1] = referenceSystemNormal[1] - dot * tangent[1];
    projectedReferenceSystemNormal[2] = referenceSystemNormal[2] - dot * tangent[2];
    vtkMath::Normalize(projectedReferenceSystemNormal);

    double angle = vtkvmtkMath::AngleBetweenNormals(normal,projectedReferenceSystemNormal);
    
    double cross[3];
    vtkMath::Cross(projectedReferenceSystemNormal,normal,cross);
    double tangentDot = vtkMath::Dot(tangent,cross);

    if (tangentDot < 0.0)
      {
      angle *= -1.0;
      }
    
    double angleOffset = -angle;

    vtkIdList* centerlineCellIds = vtkIdList::New();
    vtkvmtkCenterlineUtilities::GetCenterlineCellIds(input,this->CenterlineIdsArrayName,centerlineId,centerlineCellIds);
    for (int j=0; j<centerlineCellIds->GetNumberOfIds(); j++)
    {
      vtkCell* branchCell = input->GetCell(centerlineCellIds->GetId(j));
      int numberOfBranchPoints = branchCell->GetNumberOfPoints();
      for (int k=0; k<numberOfBranchPoints; k++)
        {
        vtkIdType branchPointId = branchCell->GetPointId(k);
        double branchPointAbscissa = abscissasArray->GetComponent(branchPointId,0);
        double offsetBranchPointAbscissa = branchPointAbscissa + abscissaOffset;
        offsetAbscissasArray->SetComponent(branchPointId,0,offsetBranchPointAbscissa);

        double branchPointNormal[3];
        normalsArray->GetTuple(branchPointId,branchPointNormal);
        double branchPoint[3];
        branchCell->GetPoints()->GetPoint(k,branchPoint);
        double branchTangent[3];
        branchTangent[0] = branchTangent[1] = branchTangent[2] = 0.0;
        if (k > 0)
          {
          double branchPoint0[3];
          branchCell->GetPoints()->GetPoint(k-1,branchPoint0);
          branchTangent[0] += branchPoint[0] - branchPoint0[0];
          branchTangent[1] += branchPoint[1] - branchPoint0[1];
          branchTangent[2] += branchPoint[2] - branchPoint0[2];
          }
        if (k < numberOfBranchPoints-1)
          {
          double branchPoint1[3];
          branchCell->GetPoints()->GetPoint(k+1,branchPoint1);
          branchTangent[0] += branchPoint1[0] - branchPoint[0];
          branchTangent[1] += branchPoint1[1] - branchPoint[1];
          branchTangent[2] += branchPoint1[2] - branchPoint[2];
          }
        double branchNormalDot = vtkMath::Dot(branchTangent,branchPointNormal);
        branchTangent[0] -= branchNormalDot * branchPointNormal[0];
        branchTangent[1] -= branchNormalDot * branchPointNormal[1];
        branchTangent[2] -= branchNormalDot * branchPointNormal[2];
        vtkMath::Normalize(branchTangent);

        vtkTransform* transform = vtkTransform::New();
        transform->RotateWXYZ(angleOffset/vtkMath::Pi()*180.0,branchTangent);

        double offsetBranchPointNormal[3];
        transform->TransformNormal(branchPointNormal,offsetBranchPointNormal);
        offsetNormalsArray->SetTuple(branchPointId,offsetBranchPointNormal);

        transform->Delete();
        }
      }
    centerlineCellIds->Delete();
    }

  groupCellIds->Delete();
  
  output->GetPointData()->AddArray(offsetAbscissasArray);
  output->GetPointData()->AddArray(offsetNormalsArray);

  offsetAbscissasArray->Delete();
  offsetNormalsArray->Delete();
  tube->Delete();
  tubeInputCellIds->Delete();

  return 1;
}

void vtkvmtkCenterlineReferenceSystemAttributesOffset::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


<|start_filename|>vtkVmtk/Segmentation/vtkvmtkMedialCurveFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkMedialCurveFilter.h,v $
Language:  C++
Date:      $Date: 2018/04/09 16:48:25 $
Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.
  Note: this class was contributed by 
      <NAME>
      https://github.com/rlizzo

=========================================================================*/
// .NAME vtkvmtkMedialCurveFilter - flux driven automatic centerline extraction from a surface
// .SECTION Description
// Please see http://www.insight-journal.org/browse/publication/165 for source implementation. 
// 
// Implementation of the flux driven automatic centerline extraction algorithm proposed by Bouix et al. in 2004. This is based on a skeletonisation algorithm initially proposed by Siddiqi et al. in 2002, using properties of an average outward flux measure to distinguish skeletal points from non-skeletal ones. This information is combined with a topology preserving thinning procedure to obtain the final result. This implementation combines this skeletonisation algorithm with other techniques as described in the paper of Bouix et al. to produce an ITK filter that generates as output the skeleton, as a binary object represented in an image, of the input surface, represented as a distance transform image. In this work is described this medial curve extraction procedure following the ITK philosophy.


#ifndef __vtkvmtkMedialCurveFilter_h
#define __vtkvmtkMedialCurveFilter_h

#include "vtkSimpleImageToImageFilter.h"
#include "vtkImageData.h"
#include "vtkvmtkWin32Header.h"

class vtkImageData;
class itkImage;

class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkMedialCurveFilter : public vtkSimpleImageToImageFilter
{
  public:

    static vtkvmtkMedialCurveFilter *New();
    vtkTypeMacro(vtkvmtkMedialCurveFilter, vtkSimpleImageToImageFilter);
    // void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

    vtkGetMacro(Sigma,double);
    vtkSetMacro(Sigma,double);

    vtkGetMacro(Threshold,double);
    vtkSetMacro(Threshold,double);

  protected:
    vtkvmtkMedialCurveFilter();
    ~vtkvmtkMedialCurveFilter();

    virtual void SimpleExecute(vtkImageData* input, vtkImageData* output) VTK_OVERRIDE;

    double Sigma;
    double Threshold;

  private:
    vtkvmtkMedialCurveFilter(const vtkvmtkMedialCurveFilter&);  // Not implemented.
    void operator=(const vtkvmtkMedialCurveFilter&);  // Not implemented.
};
#endif

<|start_filename|>vtkVmtk/Utilities/OpenNL/nl.h<|end_filename|>
/*
 *  Copyright (c) 2004-2010, <NAME>
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *  * Neither the name of the ALICE Project-Team nor the names of its
 *  contributors may be used to endorse or promote products derived from this
 *  software without specific prior written permission.
 * 
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 *  If you modify this software, you should include a notice giving the
 *  name of the person performing the modification, the date of modification,
 *  and the reason for such modification.
 *
 *  Contact: <NAME>
 *
 *     <EMAIL>
 *
 *     ALICE Project
 *     LORIA, INRIA Lorraine, 
 *     Campus Scientifique, BP 239
 *     54506 VANDOEUVRE LES NANCY CEDEX 
 *     FRANCE
 *
 */

#ifndef __LIBNL_LINKAGE__
#define __LIBNL_LINKAGE__

#ifdef WIN32
    #ifdef NL_SHARED_LIBS
        #ifdef NL_EXPORTS
            #define NLAPIENTRY __declspec( dllexport )
        #else
            #define NLAPIENTRY __declspec( dllimport )
        #endif
    #else
        #define NLAPIENTRY
    #endif
#else
    #define NLAPIENTRY
#endif

#endif
/*
 *  Copyright (c) 2004-2010, <NAME>
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *  * Neither the name of the ALICE Project-Team nor the names of its
 *  contributors may be used to endorse or promote products derived from this
 *  software without specific prior written permission.
 * 
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 *  If you modify this software, you should include a notice giving the
 *  name of the person performing the modification, the date of modification,
 *  and the reason for such modification.
 *
 *  Contact: <NAME>
 *
 *     <EMAIL>
 *
 *     ALICE Project
 *     LORIA, INRIA Lorraine, 
 *     Campus Scientifique, BP 239
 *     54506 VANDOEUVRE LES NANCY CEDEX 
 *     FRANCE
 *
 */


#ifndef __nl_h__
#define __nl_h__

#ifdef __cplusplus
extern "C" {
#endif

#define NL_VERSION_0_0 1

#define NLAPI



/*
 *
 * Datatypes
 *
 */

typedef unsigned int	NLenum;
typedef unsigned char	NLboolean;
typedef unsigned int	NLbitfield;
typedef void		NLvoid;
typedef signed char	NLbyte;		/* 1-byte signed */
typedef short		NLshort;	/* 2-byte signed */
typedef int		NLint;		/* 4-byte signed */
typedef unsigned char	NLubyte;	/* 1-byte unsigned */
typedef unsigned short	NLushort;	/* 2-byte unsigned */
typedef unsigned int	NLuint;		/* 4-byte unsigned */
typedef int		NLsizei;	/* 4-byte signed */
typedef float		NLfloat;	/* single precision float */
typedef double		NLdouble;	/* double precision float */

typedef void* NLContext ;

/*
 *
 * Constants
 *
 */

#define NL_FALSE   0x0
#define NL_TRUE    0x1

/* Primitives */

#define NL_SYSTEM  0x0
#define NL_MATRIX  0x1
#define NL_ROW     0x2


/* Solver Parameters */

#define NL_SOLVER           0x100
#define NL_NB_VARIABLES     0x101
#define NL_LEAST_SQUARES    0x102
#define NL_MAX_ITERATIONS   0x103
#define NL_THRESHOLD        0x104
#define NL_OMEGA            0x105
#define NL_SYMMETRIC        0x106
#define NL_USED_ITERATIONS  0x107
#define NL_ERROR            0x108
#define NL_INNER_ITERATIONS 0x109
#define NL_ELAPSED_TIME     0x10a
#define NL_PRECONDITIONER   0x10b

/* Solvers */

#define NL_CG                    0x200
#define NL_BICGSTAB              0x201
#define NL_GMRES                 0x202
#define NL_SUPERLU_EXT           0x210
#define NL_PERM_SUPERLU_EXT      0x211
#define NL_SYMMETRIC_SUPERLU_EXT 0x212
#define NL_SOLVER_USER           0x213

#define NL_CNC_FLOAT_CRS         0x220
#define NL_CNC_DOUBLE_CRS        0x222
#define NL_CNC_FLOAT_BCRS2       0x221
#define NL_CNC_DOUBLE_BCRS2      0x223
#define NL_CNC_FLOAT_ELL         0x224
#define NL_CNC_DOUBLE_ELL        0x225
#define NL_CNC_FLOAT_HYB         0x229
#define NL_CNC_DOUBLE_HYB        0x22a

/* Preconditioners */

#define NL_PRECOND_NONE       0x000
#define NL_PRECOND_JACOBI     0x300
#define NL_PRECOND_SSOR       0x301
#define NL_PRECOND_USER       0x303

/* Enable / Disable */

#define NL_NORMALIZE_ROWS  0x400

/* Row parameters */

#define NL_RIGHT_HAND_SIDE 0x500
#define NL_ROW_SCALING     0x501

/* Functions */

#define NL_FUNC_SOLVER         0x600
#define NL_FUNC_MATRIX         0x601
#define NL_FUNC_PRECONDITIONER 0x602

/*
 * Contexts
 */
    NLAPI NLContext NLAPIENTRY nlNewContext() ;
    NLAPI void NLAPIENTRY nlDeleteContext(NLContext context) ;
    NLAPI void NLAPIENTRY nlMakeCurrent(NLContext context) ;
    NLAPI NLContext NLAPIENTRY nlGetCurrent() ;
    NLAPI NLboolean NLAPIENTRY nlInitExtension(const char* extension) ;

/*
 * State set/get
 */

    NLAPI void NLAPIENTRY nlSolverParameterd(NLenum pname, NLdouble param) ;
    NLAPI void NLAPIENTRY nlSolverParameteri(NLenum pname, NLint param) ;

    NLAPI void NLAPIENTRY nlRowParameterd(NLenum pname, NLdouble param) ;
    NLAPI void NLAPIENTRY nlRowParameteri(NLenum pname, NLint param) ;

    NLAPI void NLAPIENTRY nlGetBooleanv(NLenum pname, NLboolean* params) ;
    NLAPI void NLAPIENTRY nlGetDoublev(NLenum pname, NLdouble* params) ;
    NLAPI void NLAPIENTRY nlGetIntergerv(NLenum pname, NLint* params) ;

    NLAPI void NLAPIENTRY nlEnable(NLenum pname) ;
    NLAPI void NLAPIENTRY nlDisable(NLenum pname) ;
    NLAPI NLboolean nlIsEnabled(NLenum pname) ;

/*
 * Functions
 */
    NLAPI void NLAPIENTRY nlSetFunction(NLenum pname, void* param) ;
    NLAPI void NLAPIENTRY nlGetFunction(NLenum pname, void** param) ;

/*
 * Variables
 */
    NLAPI void NLAPIENTRY nlSetVariable(NLuint index, NLdouble value) ;
    NLAPI NLdouble NLAPIENTRY nlGetVariable(NLuint index) ;
    NLAPI void NLAPIENTRY nlLockVariable(NLuint index) ;
    NLAPI void NLAPIENTRY nlUnlockVariable(NLuint index) ;
    NLAPI NLboolean NLAPIENTRY nlVariableIsLocked(NLuint index) ;

/*
 * Begin/End
 */

    NLAPI void NLAPIENTRY nlBegin(NLenum primitive) ;
    NLAPI void NLAPIENTRY nlEnd(NLenum primitive) ;
    NLAPI void NLAPIENTRY nlCoefficient(NLuint index, NLdouble value) ;

/*
 * Solve
 */

    NLAPI NLboolean NLAPIENTRY nlSolve() ;
    


#ifdef __cplusplus
}
#endif

#endif


<|start_filename|>vtkVmtk/Segmentation/itkSymmetricEigenVectorAnalysisImageFilter.h<|end_filename|>
/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: itkSymmetricEigenVectorAnalysisImageFilter.h,v $
  Language:  C++
  Date:      $Date: 2007/03/30 17:58:14 $
  Version:   $Revision: 1.2 $

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef __itkSymmetricEigenVectorAnalysisImageFilter_h
#define __itkSymmetricEigenVectorAnalysisImageFilter_h

#include "itkUnaryFunctorImageFilter.h"
#include "itkSymmetricEigenAnalysis.h"


namespace itk
{

// This functor class invokes the computation of Eigen Analysis for
// every pixel. The input pixel type must provide the API for the [][]
// operator, while the output pixel type must provide the API for the
// [] operator. Input pixel matrices should be symmetric.
// 
// The default operation is to order eigen values in ascending order.
// You may also use OrderEigenValuesBy( ) to order eigen values by
// magnitude as is common with use of tensors in vessel extraction.
namespace Functor {  
 
template< typename TInput, typename TOutput, typename TMatrix >
class SymmetricEigenVectorAnalysisFunction
{
public:
  SymmetricEigenVectorAnalysisFunction() {}
  ~SymmetricEigenVectorAnalysisFunction() {}
  typedef SymmetricEigenAnalysis< TInput, TOutput, TMatrix > CalculatorType;
  bool operator!=( const SymmetricEigenVectorAnalysisFunction & ) const
  {
    return false;
  }
  bool operator==( const SymmetricEigenVectorAnalysisFunction & other ) const
  {
    return !(*this != other);
  }

  inline TMatrix operator()( const TInput & x )
    {
    TOutput      eigenValues;
    TMatrix eigenVectorMatrix;
    m_Calculator.ComputeEigenValuesAndVectors( x, eigenValues, eigenVectorMatrix );
    return eigenVectorMatrix;
    }

  /** Method to explicitly set the dimension of the matrix */
  void SetDimension( unsigned int n )
    {
    m_Calculator.SetDimension(n);
    }

  /** Typdedefs to order eigen values. 
   * OrderByValue:      lambda_1 < lambda_2 < ....
   * OrderByMagnitude:  |lambda_1| < |lambda_2| < .....
   * DoNotOrder:        Default order of eigen values obtained after QL method
   */
  typedef enum {
    OrderByValue=1,
    OrderByMagnitude,
    DoNotOrder
  }EigenValueOrderType;
 
  /** Order eigen values. Default is to OrderByValue:  lambda_1 < lambda_2 < ....*/
  void OrderEigenValuesBy( EigenValueOrderType order )
    {
    if( order == OrderByMagnitude )
      {
      m_Calculator.SetOrderEigenMagnitudes( true );
      }
    else if( order == DoNotOrder )
      {
      m_Calculator.SetOrderEigenValues( false );
      }
    }

private:
  CalculatorType m_Calculator;
}; 

}  // end namespace functor


/** \class SymmetricEigenVectorAnalysisImageFilter
 * 
 * \ingroup IntensityImageFilters  Multithreaded  TensorObjects
 *
 */
template <typename  TInputImage, typename  TOutputImage, typename TOutputMatrix>
class ITK_EXPORT SymmetricEigenVectorAnalysisImageFilter :
    public
UnaryFunctorImageFilter<TInputImage,TOutputMatrix, 
                        Functor::SymmetricEigenVectorAnalysisFunction< 
                                        typename TInputImage::PixelType,
                                        typename TOutputImage::PixelType,
                                        typename TOutputMatrix::PixelType > >
{
public:
  /** Standard class typedefs. */
  typedef SymmetricEigenVectorAnalysisImageFilter  Self;
  typedef UnaryFunctorImageFilter<TInputImage,TOutputMatrix, 
                                  Functor::SymmetricEigenVectorAnalysisFunction< 
                                        typename TInputImage::PixelType,
                                        typename TOutputImage::PixelType,
                                        typename TOutputMatrix::PixelType > >
                                                                      Superclass;

  typedef SmartPointer<Self>   Pointer;
  typedef SmartPointer<const Self>  ConstPointer;

  typedef typename Superclass::OutputImageType    OutputImageType;
  typedef typename TOutputImage::PixelType        OutputPixelType;
  typedef typename TInputImage::PixelType         InputPixelType;
  typedef typename Superclass::FunctorType        FunctorType; 

  /** Typdedefs to order eigen values. 
   * OrderByValue:      lambda_1 < lambda_2 < ....
   * OrderByMagnitude:  |lambda_1| < |lambda_2| < .....
   * DoNotOrder:        Default order of eigen values obtained after QL method
   */
  typedef typename FunctorType::EigenValueOrderType         EigenValueOrderType;
 
  /** Order eigen values. Default is to OrderByValue:  lambda_1 < lambda_2 < ....*/
  void OrderEigenValuesBy( EigenValueOrderType order )
    {
    this->GetFunctor().OrderEigenValuesBy( order );
    }

  /** Method for creation through the object factory. */
  itkNewMacro(Self);
  
  /** Print internal ivars */
  void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE
    { this->Superclass::PrintSelf( os, indent ); }
  
  /** Set the dimension of the tensor. (For example the SymmetricSecondRankTensor
   * is a pxp matrix) */
  void SetDimension( unsigned int p )
    {
    this->GetFunctor().SetDimension(p);
    }

protected:
  SymmetricEigenVectorAnalysisImageFilter() {};
  virtual ~SymmetricEigenVectorAnalysisImageFilter() {};

private:
  SymmetricEigenVectorAnalysisImageFilter(const Self&); //purposely not implemented
  void operator=(const Self&); //purposely not implemented

};


  
} // end namespace itk
  
#endif


<|start_filename|>vtkVmtk/Segmentation/vtkvmtkRecursiveGaussian2DImageFilter.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkbvsRecursiveGaussian2DImageFilter.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkRecursiveGaussian2DImageFilter.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkITKFilterUtilities.h"

#include "itkRecursiveGaussianImageFilter.h"

vtkStandardNewMacro(vtkvmtkRecursiveGaussian2DImageFilter);

vtkvmtkRecursiveGaussian2DImageFilter::vtkvmtkRecursiveGaussian2DImageFilter()
{
  this->Sigma = 1.0;
  this->NormalizeAcrossScale = 0;
}

void vtkvmtkRecursiveGaussian2DImageFilter::SimpleExecute(vtkImageData* input, vtkImageData* output)
{
  typedef float PixelType;
  const int Dimension = 2;
  typedef itk::Image<PixelType, Dimension> ImageType;

  ImageType::Pointer inImage = ImageType::New();

  vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(input,inImage);

  typedef itk::RecursiveGaussianImageFilter<ImageType,ImageType> GaussianFilterType;

  GaussianFilterType::Pointer gaussianFilter = GaussianFilterType::New();
  gaussianFilter->SetInput(inImage);
  gaussianFilter->SetSigma(this->Sigma);
  gaussianFilter->SetNormalizeAcrossScale(this->NormalizeAcrossScale);
  gaussianFilter->Update();

  ImageType::Pointer outputImage = gaussianFilter->GetOutput();

  vtkvmtkITKFilterUtilities::ITKToVTKImage<ImageType>(outputImage,output);
}



<|start_filename|>vtkVmtk/Segmentation/vtkvmtkObjectnessMeasureImageFilter.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkbvsObjectnessMeasureImageFilter.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkObjectnessMeasureImageFilter.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkITKFilterUtilities.h"

#include "itkMultiScaleHessianBasedMeasureImageFilter.h"
#include "itkHessianToObjectnessMeasureImageFilter.h"

vtkStandardNewMacro(vtkvmtkObjectnessMeasureImageFilter);

vtkvmtkObjectnessMeasureImageFilter::vtkvmtkObjectnessMeasureImageFilter()
{
  this->SigmaMin = 1.0;
  this->SigmaMax = 1.0;
  this->NumberOfSigmaSteps = 1;
  this->SigmaStepMethod = EQUISPACED;
  this->UseScaledObjectness = 0;
  this->Alpha = 1.0;
  this->Beta = 1.0;
  this->Gamma = 1.0;
  this->ObjectDimension = 1;
  this->ScalesOutput = NULL;
}

vtkvmtkObjectnessMeasureImageFilter::~vtkvmtkObjectnessMeasureImageFilter()
{
  if (this->ScalesOutput)
    {
      this->ScalesOutput->Delete();
      this->ScalesOutput = NULL;
    }
}

void vtkvmtkObjectnessMeasureImageFilter::SimpleExecute(vtkImageData* input, vtkImageData* output)
{
  typedef itk::Image<float,3> ImageType;

  ImageType::Pointer inImage = ImageType::New();

  vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(input,inImage);

  typedef itk::SymmetricSecondRankTensor<float,3> HessianPixelType;
  typedef itk::Image<HessianPixelType,3> HessianImageType;
  typedef itk::HessianToObjectnessMeasureImageFilter<HessianImageType,ImageType> ObjectnessFilterType;
  typedef itk::MultiScaleHessianBasedMeasureImageFilter<ImageType,HessianImageType,ImageType> MultiScaleFilterType;
  typedef MultiScaleFilterType::ScalesImageType ScalesImageType;

  ObjectnessFilterType::Pointer objectnessFilter = ObjectnessFilterType::New();
  objectnessFilter->SetScaleObjectnessMeasure(this->UseScaledObjectness);
  objectnessFilter->SetBrightObject(true);
  objectnessFilter->SetObjectDimension(this->ObjectDimension);
  objectnessFilter->SetAlpha(this->Alpha);
  objectnessFilter->SetBeta(this->Beta);
  objectnessFilter->SetGamma(this->Gamma);

  MultiScaleFilterType::Pointer multiScaleFilter = MultiScaleFilterType::New();
  multiScaleFilter->SetInput(inImage);
  multiScaleFilter->SetSigmaMinimum(this->SigmaMin);
  multiScaleFilter->SetSigmaMaximum(this->SigmaMax);
  multiScaleFilter->SetNumberOfSigmaSteps(this->NumberOfSigmaSteps);
  if (this->SigmaStepMethod == EQUISPACED)
    {
      multiScaleFilter->SetSigmaStepMethodToEquispaced();
    }
  else if (this->SigmaStepMethod == LOGARITHMIC)
    {
      multiScaleFilter->SetSigmaStepMethodToLogarithmic();
    }
  multiScaleFilter->GenerateScalesOutputOn();
  multiScaleFilter->SetHessianToMeasureFilter(objectnessFilter);
  multiScaleFilter->Update();

  if (this->ScalesOutput)
    {
      this->ScalesOutput->Delete();
      this->ScalesOutput = NULL;
    }

  this->ScalesOutput = vtkImageData::New();

  ScalesImageType::Pointer scalesImage = const_cast<ScalesImageType*>(multiScaleFilter->GetScalesOutput());

  vtkvmtkITKFilterUtilities::ITKToVTKImage<ScalesImageType>(scalesImage,this->ScalesOutput);

  vtkvmtkITKFilterUtilities::ITKToVTKImage<ImageType>(multiScaleFilter->GetOutput(),output);
}



<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/quality.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*  tetrahedron quality functions                                            */
/*                                                                           */
/*****************************************************************************/

/* determine if a tet has any boundary vertices.
   return the number of boundary verts as well as
   their tags in boundtags */
int boundverts(struct tetcomplex *mesh,
               tag vtx1,
               tag vtx2,
               tag vtx3,
               tag vtx4,
               tag boundtags[])
{
    int i,j,k,l;     /* loop indices */
    bool noghosts;   /* any ghost tets incident to this vertex? */
    tag tet[4];      /* array version of tet indices */
    int numincident; /* number of incident tets */
    int numbound=0;  /* number of boundary verts */
    /* a list of all the tets incident to this vertex */
    tag incidenttettags[MAXINCIDENTTETS][4];
    
    tet[0] = vtx1;
    tet[1] = vtx2;
    tet[2] = vtx3;
    tet[3] = vtx4;
    
    /* check each vertex */
    for (i = 0; i < 4; i++) 
    {
        j = (i + 1) & 3;
        if ((i & 1) == 0) {
            l = (i + 3) & 3;
            k = (i + 2) & 3;
        } else {
            l = (i + 2) & 3;
            k = (i + 3) & 3;
        }
        
        /* get all the tets incident to this vertex. */
        numincident = 0;
        noghosts = true;
        getincidenttets(mesh, 
                        tet[i],
                        tet[j],
                        tet[k],
                        tet[l], 
                        incidenttettags,
                        &numincident,
                        &noghosts);
        
        /* is this a boundary vertex? */
        if (noghosts == false)
        {
            boundtags[numbound] = tet[i];
            numbound++;
        }
    }
    
    return numbound;
}

/* Retrieve the ring of tetrahedra around a particular edge, and meanwhile
   detect whether it's a boundary edge. Potentially don't store the ring of
   tets if the array to store them is null. Return a boolean indicating 
   whether it is a bounary edge, as well as the third vertices of the boundary
   faces */
#define NOBOUNDFACE -2
bool getedgering(struct tetcomplex *mesh,
                 tag vtx1, /* first vertex of the edge */
                 tag vtx2, /* second vertex of the edge */
                 tag vtx3, /* third vertex of a tet that contains the edge */
                 tag vtx4, /* fourth vertex of a tet that contains the edge */
                 int *numringtets, /* number of tets in the ring */
                 tag ringtets[MAXRINGTETS][4], /* the vertices of tets in the ring */
                 tag boundfaceverts[2] /* the third vertex of the two boundary faces */
                )
{
    tag ring[MAXRINGTETS]; /* array of tags for ring of vertices around edge */
    tag start;             /* the first vertex tag in an edge's ring */
    int ringcount = 0;     /* the number of vertices found in the ring so far */
    tag nextprev[2];       /* the next and previous vertices around the ring */
    int foundface;         /* indicates whether the face in the adj query exists */
    bool reverse = false;  /* for going back to find the other boundary face */
    bool forward = true;
    tag ev1, ev2;          /* first and second edge vertex */
    
    /* initialize boundary face vertex tags to cardinal value */
    boundfaceverts[0] = boundfaceverts[1] = (tag) NOBOUNDFACE;
    
    /* we will proceed around the ring of tets surrounding an edge by using
       repeated face adjancency queries until we reach the start of the ring
       again. If at any point we encounter a ghost tetrahedron, we'll know 
       that this edge must lie on the boundary, and to complete the ring we
       must return to the begining and proceed around the other direction */
    
    /* if we're recording the identity of the tets in the ring */
    if (numringtets != NULL)
    {
        *numringtets = 0;
        
        /* record the first tetrahedron in the ring, which is just
           the input tet. take care to record the edge verts as the
           first two */
        ringtets[*numringtets][0] = vtx1;
        ringtets[*numringtets][1] = vtx2;
        ringtets[*numringtets][2] = vtx3;
        ringtets[*numringtets][3] = vtx4;
        assert(tetexistsa(mesh, ringtets[*numringtets]));
        (*numringtets)++;
    }
    
    /* start by going one way around the edge. If we find a boundary face,
       then look back the other way */
    while (forward || reverse)
    {
        forward = false;
        
        /* the first vertex in the ring is set to another vertex in the
           current tet. We choose one that will orient the first face adjacency
           query out of the current tet: if the edge is ij, the third vertex is k
           swap order for reverse rotation. */
        start = (reverse) ? vtx4 : vtx3;
        ev1 = (reverse) ? vtx2 : vtx1;
        ev2 = (reverse) ? vtx1 : vtx2;
        ring[0] = start;
        ringcount = 0;
        
        /* now, use adjacency tests to move around the ring, until we get back where
           we started or the ring gets too big*/
        foundface = tetcomplexadjacencies(mesh, ev1, ev2, start, nextprev);
        assert(foundface == 1);
        assert(nextprev[1] == ((reverse) ? vtx3 : vtx4));
        
        /* check if we are at the boundary */
        if (nextprev[0] == GHOSTVERTEX)
        {
            /* record the identity of the face where we hit the boundary */
            if (reverse == false)
            {
                assert(boundfaceverts[0] == NOBOUNDFACE);
                boundfaceverts[0] = ring[ringcount];
            }
            else
            {
                assert(boundfaceverts[0] != NOBOUNDFACE);
                boundfaceverts[1] = ring[ringcount];
            }
            
            if (improvebehave.verbosity > 5)
            {
                printf("on first ring query found bound face with vert %d, reverse=%d\n", (int) ring[ringcount], (int) reverse);
            }
            
            /* if we aren't on a reverse run already, schedule one */
            reverse = (reverse) ? false : true;
             
            /* don't try to proceed any further around this ring */
            continue;
        }
        
        /* we found a legitimate tet next in the ring */
        ringcount++;
        
        /* as long as we don't complete the ring, keep moving around */
        while ((ringcount < MAXRINGTETS) && (nextprev[0] != start))
        {
            /* add the next vertex to the ring */
            ring[ringcount] = nextprev[0];
            
            /* record the new tet in the ring */
            if (numringtets != NULL)
            {
                /* we found a tet! record it the list of tets, always
                   recording the two edge vertices first */
                ringtets[*numringtets][0] = ev1;
                ringtets[*numringtets][1] = ev2;
                ringtets[*numringtets][2] = ring[ringcount];
                ringtets[*numringtets][3] = ring[ringcount - 1];
                assert(tetexistsa(mesh, ringtets[*numringtets]));
                (*numringtets)++;
            }
            
            /* look for next vertex */
            foundface = tetcomplexadjacencies(mesh, ev1, ev2, nextprev[0], nextprev);
            assert(foundface == 1);
            assert(nextprev[1] == ring[ringcount-1]);
            
            /* check again for ghost vertex */
            if (nextprev[0] == GHOSTVERTEX)
            {
                /* record the identity of the face where we hit the boundary */
                if (reverse == false)
                {
                    assert(boundfaceverts[0] == NOBOUNDFACE);
                    boundfaceverts[0] = ring[ringcount];
                }
                else
                {
                    assert(boundfaceverts[0] != NOBOUNDFACE);
                    boundfaceverts[1] = ring[ringcount];
                }
                
                if (improvebehave.verbosity > 5)
                {
                    printf("on query %d found bound face with vert %d, reverse=%d\n", (int) ringcount, (int) ring[ringcount], (int) reverse);
                }
                
                /* if we aren't on a reverse run already, schedule one */
                reverse = (reverse) ? false : true;
                
                /* stop looking in this direction */
                break;
            }
        
            ringcount++;
        }
    }
    
    assert(ringcount >= 0 && ringcount < MAXRINGTETS);
    
    /* we've now finished looking forward and potentially back around
       the edge. Return true if this is a boundary edge, false if not */
    if (boundfaceverts[0] != NOBOUNDFACE)
    {
        /* we must have found both boundary faces */
        assert(boundfaceverts[1] != NOBOUNDFACE);
        /* and they can't be the same */
        assert(boundfaceverts[0] != boundfaceverts[1]);
        
        return true;
    }
    return false;
}

/* returns the number of edges of this tet that lie on the boundary
   along with a list of them */
int boundedges(struct tetcomplex *mesh,
               tag vtx1,
               tag vtx2,
               tag vtx3,
               tag vtx4,
               tag edgelist[][2],
               tag edgefaces[6][2],
               int numedgetets[6],
               tag edgetets[6][MAXRINGTETS][4])
{
    tag tet[4];            /* the current tet we are trying to improve */
    int i,j,k,l;           /* loop indices for each tet vertex */
    int temp;
    bool boundedge;        /* whether a particular edge is a boundary edge */
    int numboundedges = 0; /* number of boundary edges found */
    
    tet[0] = vtx1;
    tet[1] = vtx2;
    tet[2] = vtx3;
    tet[3] = vtx4;
    
    
    for (i = 0; i < 3; i++) 
    {
        for (j = i + 1; j < 4; j++) 
        {
            k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
            l = 6 - i - j - k;
            /* to get right sequence, need to swap k and l sometimes */
            if ((i+j) % 2 == 0)
            {
                temp = k;
                k = l;
                l = temp;
            }
            
            /* now our tet is (i,j,k,l). check if this is a boundary edge */
            boundedge = getedgering(mesh, tet[i], tet[j], tet[k], tet[l],
                                    (numedgetets == NULL) ? NULL : &numedgetets[numboundedges],
                                    edgetets[numboundedges], 
                                    edgefaces[numboundedges]);
            /* if this was a boundary edge */
            if (boundedge)
            {
                /* save this edge in the list of boundary edges */
                edgelist[numboundedges][0] = tet[i];
                edgelist[numboundedges][1] = tet[j];
                numboundedges++;
            }
        }
    }
    
    return numboundedges;
}

/* determine if any of the faces of a tet lie on
   the boundary. if so, return true, and put
   the boundary faces in boundfaces */
bool boundfaces(struct tetcomplex *mesh,
                  tag vtx1,
                  tag vtx2,
                  tag vtx3,
                  tag vtx4,
                  tag boundfaces[][3],
                  int *numboundary)
{
    int foundface;
    tag topbot[2];
    
    *numboundary = 0;
    
    /* make sure this tet actually exists */
    assert(tetexists(mesh, vtx1, vtx2, vtx3, vtx4));
    
    /* check adjacencies of each face looking for ghost vertex */
    /* faces are oriented out from tet */
    foundface = tetcomplexadjacencies(mesh, vtx1, vtx2, vtx3, topbot);
    assert(foundface == 1);
    assert(topbot[1] == vtx4);
    if (topbot[0] == GHOSTVERTEX)
    {
        boundfaces[*numboundary][0] = vtx1;
        boundfaces[*numboundary][1] = vtx2;
        boundfaces[*numboundary][2] = vtx3;
        *numboundary = *numboundary + 1;
    }
    
    foundface = tetcomplexadjacencies(mesh, vtx1, vtx3, vtx4, topbot);
    assert(foundface == 1);
    assert(topbot[1] == vtx2);
    if (topbot[0] == GHOSTVERTEX)
    {
        boundfaces[*numboundary][0] = vtx1;
        boundfaces[*numboundary][1] = vtx3;
        boundfaces[*numboundary][2] = vtx4;
        *numboundary = *numboundary + 1;
    }
    
    foundface = tetcomplexadjacencies(mesh, vtx1, vtx4, vtx2, topbot);
    assert(foundface == 1);
    assert(topbot[1] == vtx3);
    if (topbot[0] == GHOSTVERTEX)
    {
        boundfaces[*numboundary][0] = vtx1;
        boundfaces[*numboundary][1] = vtx4;
        boundfaces[*numboundary][2] = vtx2;
        *numboundary = *numboundary + 1;
    }
    
    foundface = tetcomplexadjacencies(mesh, vtx2, vtx4, vtx3, topbot);
    assert(foundface == 1);
    assert(topbot[1] == vtx1);
    if (topbot[0] == GHOSTVERTEX)
    {
        boundfaces[*numboundary][0] = vtx2;
        boundfaces[*numboundary][1] = vtx4;
        boundfaces[*numboundary][2] = vtx3;
        *numboundary = *numboundary + 1;
    }
    
    if (*numboundary > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

/* returns true if any of this tet's faces lie
   on the boundary */
bool boundtet(struct tetcomplex *mesh,
              tag vtx1,
              tag vtx2,
              tag vtx3,
              tag vtx4)
{
    tag boundfacetags[4][3];
    int numboundfaces;
    return (boundfaces(mesh, vtx1, vtx2, vtx3, vtx4, boundfacetags, &numboundfaces) == true);
}

/* generate a list of all boundary faces in the mesh */
void getsurface(struct tetcomplex *mesh,
                struct arraypool *facepool,
                int *numfaces)
{
    struct tetcomplexposition pos;
    tag tet[4];         /* current tet */
    tag tetfaces[4][3]; /* a list of boundary faces for the current tet */
    int numtetfaces;    /* the number of boundary faces for the current tet */
    int i;
    tag *newface;       /* pointer to new face in pool */
    
    *numfaces = 0;
    
    tetcomplexiteratorinit(mesh, &pos);
    tetcomplexiteratenoghosts(&pos, tet);
    
    /* get boundary faces of all tets */
    while (tet[0] != STOP) 
    {
        /* does this tet have any boundary faces? */
        if (boundfaces(mesh, tet[0], tet[1], tet[2], tet[3], tetfaces, &numtetfaces))
        {
            /* if so, copy them to the pool of surface faces */
            for (i=0; i<numtetfaces; i++)
            {
                /* allocate a new face in the array pool */
                newface = (tag *) arraypoolforcelookup(facepool, (unsigned long) *numfaces);
                
                /* assign vertices from this face */
                newface[0] = tetfaces[i][0];
                newface[1] = tetfaces[i][1];
                newface[2] = tetfaces[i][2];
                
                /* increment count of faces */
                *numfaces = *numfaces + 1;
            }
        }
        
        tetcomplexiteratenoghosts(&pos, tet);
    }
}

/* return the volume of a tetrahedron */
starreal tetvolume(struct tetcomplex *mesh,
                   tag vtx1,
                   tag vtx2,
                   tag vtx3,
                   tag vtx4)
{
    starreal point[4][3];      /* the vertices of the tet */
    starreal E[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
    int i;
    
    /* get tet vertices */
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx1))->coord, point[0]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx2))->coord, point[1]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx3))->coord, point[2]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx4))->coord, point[3]);
    
    /* if anisotropic meshing is enabled, warp the points according the
       deformation tensor at their barycenter */
    if (improvebehave.anisotropic)
    {
        /* fetch the deformation tensor at the barycenter of this tet */
        tettensor(mesh, vtx1, vtx2, vtx3, vtx4, E);
        
        /* transform each vertex */
        for (i=0; i<4; i++)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("In tetvolume transforming point (%g %g %g) ->", point[i][0], point[i][1], point[i][2]);
            }
            
            tensortransform(point[i], point[i], E);
            
            if (improvebehave.verbosity > 5)
            {
                printf(" (%g %g %g)\n", point[i][0], point[i][1], point[i][2]);
            }
        }
    }
    
    /* calculate the volume of the tetrahedron */
    return orient3d(&behave, point[0], point[1], point[2], point[3]) / 6.0;
}

/* return the length of a tet's longest (shortest) edge,
   as well as the indices of its endpoints. "getlong" 
   argument set to true computes longest, otherwise shortest */
starreal tetedge(struct tetcomplex *mesh,
                 tag vtx1,
                 tag vtx2,
                 tag vtx3,
                 tag vtx4,
                 int edge[2],
                 bool getlong)
{
    int i,j;                  /* loop indices */
    starreal point[2][3];     /* the vertices of the tet */
    starreal length;          /* the current edge length */
    starreal longest;         /* the longest (shortest) edge */
    starreal dx, dy, dz;
    starreal E[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
    tag tet[4];
    
    longest = (getlong) ? 0.0 : HUGEFLOAT;
    
    tet[0] = vtx1;
    tet[1] = vtx2;
    tet[2] = vtx3;
    tet[3] = vtx4;
    
    /* for each edge in the tet */
    for (i=0; i<3; i++)
    {
        for (j=i+1; j<4; j++)
        {
            /* get tet vertices */
            vcopy(((struct vertex *) tetcomplextag2vertex(mesh, tet[i]))->coord, point[0]);
            vcopy(((struct vertex *) tetcomplextag2vertex(mesh, tet[j]))->coord, point[1]);
            
            /* if anisotropic meshing is enabled, warp the points according the
               deformation tensor at their barycenter */
            if (improvebehave.anisotropic)
            {
                /* fetch the deformation tensor at the midpoint of this edge */
                edgetensor(mesh, tet[i], tet[j], E);

                /* transform each vertex */
                tensortransform(point[0], point[0], E);
                tensortransform(point[1], point[1], E);
            }
            
            dx = point[0][0] - point[1][0];
            dy = point[0][1] - point[1][1];
            dz = point[0][2] - point[1][2];
            length = sqrt(dx * dx + dy * dy + dz * dz);
            
            if ((length > longest && getlong) || (length < longest && (!getlong)))
            {
                longest = length;
                edge[0] = i;
                edge[1] = j;
            }
        }
    }
    
    assert(longest > 0.0);
    return longest;
}

/* compute the (square) of the minimum sine
   of all the dihedral angles in the tet defined
   by the four vertices (vtx1, vtx2, vtx3, vtx4)
*/
starreal minsine(struct tetcomplex *mesh,
                   tag vtx1,
                   tag vtx2,
                   tag vtx3,
                   tag vtx4)
{
    starreal point[4][3];      /* tet vertices */
    starreal edgelength[3][4]; /* the lengths of each of the edges of the tet */
    starreal facenormal[4][3]; /* the normals of each face of the tet */
    starreal dx, dy, dz;       /* intermediate values of edge lengths */
    starreal facearea2[4];     /* areas of the faces of the tet */
    starreal pyrvolume;        /* volume of tetrahedron */
    starreal sine2, minsine2;  /* the sine (squared) of the dihedral angle */
    int i, j, k, l;          /* loop indices */
    starreal E[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
    
    /* get tet vertices */
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx1))->coord, point[0]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx2))->coord, point[1]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx3))->coord, point[2]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx4))->coord, point[3]);
    
    /* if anisotropic meshing is enabled, warp the points according the
       deformation tensor at their barycenter */
    if (improvebehave.anisotropic)
    {
        /* fetch the deformation tensor at the barycenter of this tet */
        tettensor(mesh, vtx1, vtx2, vtx3, vtx4, E);
        
        /* transform each vertex */
        for (i=0; i<4; i++)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("in minsine transforming point (%g %g %g) ->", point[i][0], point[i][1], point[i][2]);
            }
            
            tensortransform(point[i], point[i], E);
            
            if (improvebehave.verbosity > 5)
            {
                printf(" (%g %g %g)\n", point[i][0], point[i][1], point[i][2]);
            }
        }
    }
    
    /* calculate the volume*6 of the tetrahedron */
    pyrvolume = (starreal) orient3d(&behave, point[0], point[1], point[2], point[3]);
    
    /* if the volume is zero, the quality is zero, no reason to continue */
    if (pyrvolume == 0.0)
    {
        return 0.0;
    }
    
    /* for each vertex/face of the tetrahedron */
    for (i = 0; i < 4; i++) {
        j = (i + 1) & 3;
        if ((i & 1) == 0) {
            k = (i + 3) & 3;
            l = (i + 2) & 3;
        } else {
            k = (i + 2) & 3;
            l = (i + 3) & 3;
        }
        
        /* compute the normal for each face */
        facenormal[i][0] =
            (point[k][1] - point[j][1]) * (point[l][2] - point[j][2]) -
            (point[k][2] - point[j][2]) * (point[l][1] - point[j][1]);
        facenormal[i][1] =
            (point[k][2] - point[j][2]) * (point[l][0] - point[j][0]) -
            (point[k][0] - point[j][0]) * (point[l][2] - point[j][2]);
        facenormal[i][2] =
            (point[k][0] - point[j][0]) * (point[l][1] - point[j][1]) -
            (point[k][1] - point[j][1]) * (point[l][0] - point[j][0]);
            
        /* compute (2 *area)^2 for this face */
        facearea2[i] = facenormal[i][0] * facenormal[i][0] +
            facenormal[i][1] * facenormal[i][1] +
            facenormal[i][2] * facenormal[i][2];
        
        /* compute edge lengths (squared) */
        for (j = i + 1; j < 4; j++) {
            dx = point[i][0] - point[j][0];
            dy = point[i][1] - point[j][1];
            dz = point[i][2] - point[j][2];
            edgelength[i][j] = dx * dx + dy * dy + dz * dz;
        }
    }
    
    minsine2 = HUGEFLOAT;     /* start with absurdly big value for sine */
    
    /* for each edge in the tetrahedron */
    for (i = 0; i < 3; i++) {
        for (j = i + 1; j < 4; j++) {
            k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
            l = 6 - i - j - k;
            
            /* compute the expression for minimum sine, squared, over 4 
               The reason it's over 4 is because the area values we have
               are actually twice the area squared */
            /* if either face area is zero, the sine is zero */
            if (facearea2[k] > 0 && facearea2[l] > 0)
            {
                sine2 = edgelength[i][j] / (facearea2[k] * facearea2[l]);
            }
            else
            {
                if (improvebehave.verbosity > 5) 
                {
                    printf("Encountered zero-area face.\n");
                    printf("Here is the tet (%d %d %d %d):\n", (int) vtx1, (int) vtx2, (int) vtx3, (int) vtx4);
                    printf(",\n");
                }
                sine2 = 0.0;
            }
            
            /* update minimum sine */
            if (sine2 < minsine2)
            {
                minsine2 = sine2;
            }
        }
    }
    
    return sqrt(minsine2) * pyrvolume;
}

/* compute the minimum or maximum angle of the tet defined
   by the four vertices (vtx1, vtx2, vtx3, vtx4)
*/
starreal minmaxangle(struct tetcomplex *mesh,
                     tag vtx1,
                     tag vtx2,
                     tag vtx3,
                     tag vtx4,
                     bool max)
{
    starreal point[4][3];      /* tet vertices */
    starreal edgelength[3][4]; /* the lengths of each of the edges of the tet */
    starreal facenormal[4][3]; /* the normals of each face of the tet */
    starreal dx, dy, dz;       /* intermediate values of edge lengths */
    starreal pyrvolume;        /* volume of tetrahedron */
    int i, j, k, l;          /* loop indices */
    starreal E[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
    starreal minangle = HUGEFLOAT;
    starreal maxangle = 0.0;
    starreal angle, tantheta;
    starreal dotproduct;
    
    /* get tet vertices */
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx1))->coord, point[0]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx2))->coord, point[1]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx3))->coord, point[2]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx4))->coord, point[3]);
    
    /* if anisotropic meshing is enabled, warp the points according the
       deformation tensor at their barycenter */
    if (improvebehave.anisotropic)
    {
        /* fetch the deformation tensor at the barycenter of this tet */
        tettensor(mesh, vtx1, vtx2, vtx3, vtx4, E);
        
        /* transform each vertex */
        for (i=0; i<4; i++)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("in minsine transforming point (%g %g %g) ->", point[i][0], point[i][1], point[i][2]);
            }
            
            tensortransform(point[i], point[i], E);
            
            if (improvebehave.verbosity > 5)
            {
                printf(" (%g %g %g)\n", point[i][0], point[i][1], point[i][2]);
            }
        }
    }
    
    /* calculate the volume*6 of the tetrahedron */
    pyrvolume = (starreal) orient3d(&behave, point[0], point[1], point[2], point[3]);
    
    /* for each vertex/face of the tetrahedron */
    for (i = 0; i < 4; i++) {
        j = (i + 1) & 3;
        if ((i & 1) == 0) {
            k = (i + 3) & 3;
            l = (i + 2) & 3;
        } else {
            k = (i + 2) & 3;
            l = (i + 3) & 3;
        }
        
        /* compute the normal for each face */
        facenormal[i][0] =
            (point[k][1] - point[j][1]) * (point[l][2] - point[j][2]) -
            (point[k][2] - point[j][2]) * (point[l][1] - point[j][1]);
        facenormal[i][1] =
            (point[k][2] - point[j][2]) * (point[l][0] - point[j][0]) -
            (point[k][0] - point[j][0]) * (point[l][2] - point[j][2]);
        facenormal[i][2] =
            (point[k][0] - point[j][0]) * (point[l][1] - point[j][1]) -
            (point[k][1] - point[j][1]) * (point[l][0] - point[j][0]);
        
        /* compute edge lengths (squared) */
        for (j = i + 1; j < 4; j++) {
            dx = point[i][0] - point[j][0];
            dy = point[i][1] - point[j][1];
            dz = point[i][2] - point[j][2];
            edgelength[i][j] = dx * dx + dy * dy + dz * dz;
        }
    }
    
    /* for each edge in the tetrahedron */
    for (i = 0; i < 3; i++) {
        for (j = i + 1; j < 4; j++) {
            k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
            l = 6 - i - j - k;
            
            /* compute the tangent of the angle using the tangent formula:

               tan(theta_ij) = - 6 * V * l_ij
                               --------------
                                dot(n_k, n_l)

               because this formula is accurate in the entire range.
            */
            dotproduct = dot(facenormal[k], facenormal[l]);
            
            if (dotproduct != 0.0)
            {
                tantheta = (-pyrvolume * sqrt(edgelength[i][j])) / dotproduct;
            
                /* now compute the actual angle */
                angle = atan(tantheta);
            }
            else
            {
                angle = PI / 2.0;
            }
            
            /* adjust angle for sign of dot product */
            if (dotproduct > 0)
            {
                angle += PI;
            }

            /* make negative angles positive */
            if (angle < 0)
            {
                angle += 2.0 * PI;
            }
            
            if (dotproduct == 0.0) angle = PI / 2.0;
            
            if (improvebehave.verbosity > 5)
            {
                printf("Final angle found is %g radians, or %g degrees\n", angle, angle * (180.0 / PI));
            }
            
            if (angle < minangle) minangle = angle;
            if (angle > maxangle) maxangle = angle;
        }
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("for tet, found min angle = %g (sine is %g), max angle = %g (sine is %g)\n", radtodeg(minangle), sin(minangle), radtodeg(maxangle), sin(maxangle));
        printf("minsine computation says %g\n", minsine(mesh, vtx1, vtx2, vtx3, vtx4));
        assert(radtodeg(maxangle) <= 180.0);
    }
    
    /*
    assert(radtodeg(maxangle) <= 180.0);
    assert(minangle >= 0.0);
    */
    
    if (max) return radtodeg(maxangle);
    return radtodeg(minangle);
}

/* warp the sine of the dihedral angle to penalize obtuse angles more than acute */
starreal warpsine(starreal sine)
{
    if (improvebehave.verbosity > 6)
    {
        printf("in quality, warping sine of obtuse from %g to %g\n", sine, sine * improvebehave.sinewarpfactor);
    }
    
    return sine * improvebehave.sinewarpfactor; 
}

/* compute the (square) of the minimum sine
   of all the dihedral angles in the tet defined
   by the four vertices (vtx1, vtx2, vtx3, vtx4)
*/
starreal warpedminsine(struct tetcomplex *mesh,
                   tag vtx1,
                   tag vtx2,
                   tag vtx3,
                   tag vtx4)
{
    starreal point[4][3];      /* the vertices of the tet */
    starreal edgelength[3][4]; /* the lengths of each of the edges of the tet */
    starreal facenormal[4][3]; /* the normals of each face of the tet */
    starreal dx, dy, dz;       /* intermediate values of edge lengths */
    starreal facearea2[4];     /* areas of the faces of the tet */
    starreal pyrvolume;        /* volume of tetrahedron */
    starreal sine2, minsine2;  /* the sine (squared) of the dihedral angle */
    int i, j, k, l;          /* loop indices */
    starreal E[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};

    /* get tet vertices */
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx1))->coord, point[0]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx2))->coord, point[1]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx3))->coord, point[2]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx4))->coord, point[3]);
    
    /* if anisotropic meshing is enabled, warp the points according the
       deformation tensor at their barycenter */
    if (improvebehave.anisotropic)
    {
        /* fetch the deformation tensor at the barycenter of this tet */
        tettensor(mesh, vtx1, vtx2, vtx3, vtx4, E);
        
        /* transform each vertex */
        for (i=0; i<4; i++)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("in warpedminsine transforming point (%g %g %g) ->", point[i][0], point[i][1], point[i][2]);
            }
            
            tensortransform(point[i], point[i], E);
            
            if (improvebehave.verbosity > 5)
            {
                printf(" (%g %g %g)\n", point[i][0], point[i][1], point[i][2]);
            }
        }
    }
    
    /* calculate the volume*6 of the tetrahedron */
    pyrvolume = (starreal) orient3d(&behave, point[0], point[1], point[2], point[3]);
    
    /* if the volume is zero, the quality is zero, no reason to continue */
    if (pyrvolume == 0.0)
    {
        return 0.0;
    }
    
    /* for each vertex/face of the tetrahedron */
    for (i = 0; i < 4; i++) {
        j = (i + 1) & 3;
        if ((i & 1) == 0) {
            k = (i + 3) & 3;
            l = (i + 2) & 3;
        } else {
            k = (i + 2) & 3;
            l = (i + 3) & 3;
        }
        
        /* compute the normal for each face */
        facenormal[i][0] =
            (point[k][1] - point[j][1]) * (point[l][2] - point[j][2]) -
            (point[k][2] - point[j][2]) * (point[l][1] - point[j][1]);
        facenormal[i][1] =
            (point[k][2] - point[j][2]) * (point[l][0] - point[j][0]) -
            (point[k][0] - point[j][0]) * (point[l][2] - point[j][2]);
        facenormal[i][2] =
            (point[k][0] - point[j][0]) * (point[l][1] - point[j][1]) -
            (point[k][1] - point[j][1]) * (point[l][0] - point[j][0]);
            
        /* compute (2 *area)^2 for this face */
        facearea2[i] = facenormal[i][0] * facenormal[i][0] +
            facenormal[i][1] * facenormal[i][1] +
            facenormal[i][2] * facenormal[i][2];
        
        /* compute edge lengths (squared) */
        for (j = i + 1; j < 4; j++) {
            dx = point[i][0] - point[j][0];
            dy = point[i][1] - point[j][1];
            dz = point[i][2] - point[j][2];
            edgelength[i][j] = dx * dx + dy * dy + dz * dz;
        }
    }
    
    minsine2 = HUGEFLOAT;     /* start with absurdly big value for sine */
    
    /* for each edge in the tetrahedron */
    for (i = 0; i < 3; i++) {
        for (j = i + 1; j < 4; j++) {
            k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
            l = 6 - i - j - k;
            
            /* compute the expression for minimum sine, squared, over 4 
               The reason it's over 4 is because the area values we have
               are actually twice the area squared */
            /* if either face area is zero, the sine is zero */
            if (facearea2[k] > 0 && facearea2[l] > 0)
            {
                sine2 = edgelength[i][j] / (facearea2[k] * facearea2[l]);
            }
            else
            {
                if (improvebehave.verbosity > 5) 
                {
                    printf("Encountered zero-area face.\n");
                    printf("Here is the tet (%d %d %d %d):\n", (int) vtx1, (int) vtx2, (int) vtx3, (int) vtx4);
                    printf(",\n");
                }
                sine2 = 0.0;
            }
            
            /* check whether this angle is obtuse */
            if (dot(facenormal[k],facenormal[l]) > 0)
            {
                /* if so, warp it down */
                sine2 = warpsine(sqrt(sine2));
                sine2 *= sine2;
            }
            
            /* update minimum sine */
            if (sine2 < minsine2)
            {
                minsine2 = sine2;
            }
        }
    }
    
    return sqrt(minsine2) * pyrvolume;
}

/* compute the (square) of the minimum sine
   of all the dihedral angles in the tet defined
   by the four vertices (vtx1, vtx2, vtx3, vtx4)
*/
starreal minsineandedgeratio(struct tetcomplex *mesh,
                             tag vtx1,
                             tag vtx2,
                             tag vtx3,
                             tag vtx4)
{
    starreal point[4][3];       /* the vertices of the tet */
    starreal edgelength[3][4];  /* the lengths of each of the edges of the tet */
    starreal facenormal[4][3];  /* the normals of each face of the tet */
    starreal dx, dy, dz;        /* intermediate values of edge lengths */
    starreal facearea2[4];      /* areas of the faces of the tet */
    starreal pyrvolume;         /* volume of tetrahedron */
    starreal sine2, minsine2;   /* the sine (squared) of the dihedral angle */
    starreal minsine;
    starreal shortest = HUGEFLOAT;
    starreal longest = 0.0;     /* shortest and longest edges in teh tet */
    starreal edgeratio;         /* ratio of shortest to longest edge */
    int i, j, k, l;           /* loop indices */
    
    /* get tet vertices */
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx1))->coord, point[0]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx2))->coord, point[1]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx3))->coord, point[2]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx4))->coord, point[3]);
    
    /* calculate the volume*6 of the tetrahedron */
    pyrvolume = (starreal) orient3d(&behave, point[0], point[1], point[2], point[3]);
    
    /* for each vertex/face of the tetrahedron */
    for (i = 0; i < 4; i++) {
        j = (i + 1) & 3;
        if ((i & 1) == 0) {
            k = (i + 3) & 3;
            l = (i + 2) & 3;
        } else {
            k = (i + 2) & 3;
            l = (i + 3) & 3;
        }
        
        /* compute the normal for each face */
        facenormal[i][0] =
            (point[k][1] - point[j][1]) * (point[l][2] - point[j][2]) -
            (point[k][2] - point[j][2]) * (point[l][1] - point[j][1]);
        facenormal[i][1] =
            (point[k][2] - point[j][2]) * (point[l][0] - point[j][0]) -
            (point[k][0] - point[j][0]) * (point[l][2] - point[j][2]);
        facenormal[i][2] =
            (point[k][0] - point[j][0]) * (point[l][1] - point[j][1]) -
            (point[k][1] - point[j][1]) * (point[l][0] - point[j][0]);
            
        /* compute (2 *area)^2 for this face */
        facearea2[i] = facenormal[i][0] * facenormal[i][0] +
            facenormal[i][1] * facenormal[i][1] +
            facenormal[i][2] * facenormal[i][2];
        
        /* compute edge lengths (squared) */
        for (j = i + 1; j < 4; j++) {
            dx = point[i][0] - point[j][0];
            dy = point[i][1] - point[j][1];
            dz = point[i][2] - point[j][2];
            edgelength[i][j] = dx * dx + dy * dy + dz * dz;
            
            /* keep track of longest and shortest edge */
            if (edgelength[i][j] > longest) longest = edgelength[i][j];
            if (edgelength[i][j] < shortest) shortest = edgelength[i][j];
        }
    }
    
    minsine2 = 10.0e10;     /* start with absurdly big value for sine */
    
    /* for each edge in the tetrahedron */
    for (i = 0; i < 3; i++) {
        for (j = i + 1; j < 4; j++) {
            k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
            l = 6 - i - j - k;
            
            /* compute the expression for minimum sine, squared, over 4 
               The reason it's over 4 is because the area values we have
               are actually twice the area squared */
            /* if either face area is zero, the sine is zero */
            if (facearea2[k] > 0 && facearea2[l] > 0)
            {
                sine2 = edgelength[i][j] / (facearea2[k] * facearea2[l]);
            }
            else
            {
                if (improvebehave.verbosity > 5) 
                {
                    printf("Encountered zero-area face.\n");
                    printf("Here is the tet (%d %d %d %d):\n", (int) vtx1, (int) vtx2, (int) vtx3, (int) vtx4);
                    printf(",\n");
                }
                sine2 = 0.0;
            }
            /* update minimum sine */
            if (sine2 < minsine2)
            {
                minsine2 = sine2;
            }
        }
    }
    
    /* edge ratio, scaled down for parity with sin of equilateral tet's dihedrals */
    edgeratio = sqrt(shortest / longest) * SINEEQUILATERAL;
    minsine = sqrt(minsine2) * pyrvolume;
    
    if (improvebehave.verbosity > 5)
    {
        printf("longest edge is %g, shortest edge is %g, ratio is %g\n", sqrt(longest), sqrt(shortest), edgeratio);
        printf("minsine is %g\n", minsine);
    }
    
    if (edgeratio < minsine) 
    {
        if (improvebehave.verbosity > 5)
        {
            printf("edge ratio dominates! edgeratio = %g, minsine = %g\n", edgeratio, minsine);
        }
        return edgeratio;
    }
    return minsine;
}

/* compute the mean of the sines
   of all the dihedral angles in the tet defined
   by the four vertices (vtx1, vtx2, vtx3, vtx4)
*/
starreal meansine(struct tetcomplex *mesh,
                   tag vtx1,
                   tag vtx2,
                   tag vtx3,
                   tag vtx4)
{
    starreal *point[4];      /* the vertices of the tet */
    starreal edgelength[3][4]; /* the lengths of each of the edges of the tet */
    starreal facenormal[4][3]; /* the normals of each face of the tet */
    starreal dx, dy, dz;       /* intermediate values of edge lengths */
    starreal facearea2[4];     /* areas of the faces of the tet */
    starreal pyrvolume;        /* volume of tetrahedron */
    starreal sine2;            /* the sine (squared) of the dihedral angle */
    starreal sinesum=0.0;      /* the accumulating sum of the sines */
    int i, j, k, l;          /* loop indices */
    
    /* get tet vertices */
    point[0] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx1))->coord;
    point[1] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx2))->coord;
    point[2] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx3))->coord;
    point[3] = ((struct vertex *) tetcomplextag2vertex(mesh, vtx4))->coord;
    
    /* calculate the volume*6 of the tetrahedron */
    pyrvolume = (starreal) orient3d(&behave, point[0], point[1], point[2], point[3]);
    
    /* for each vertex/face of the tetrahedron */
    for (i = 0; i < 4; i++) {
        j = (i + 1) & 3;
        if ((i & 1) == 0) {
            k = (i + 3) & 3;
            l = (i + 2) & 3;
        } else {
            k = (i + 2) & 3;
            l = (i + 3) & 3;
        }
        
        /* compute the normal for each face */
        facenormal[i][0] =
            (point[k][1] - point[j][1]) * (point[l][2] - point[j][2]) -
            (point[k][2] - point[j][2]) * (point[l][1] - point[j][1]);
        facenormal[i][1] =
            (point[k][2] - point[j][2]) * (point[l][0] - point[j][0]) -
            (point[k][0] - point[j][0]) * (point[l][2] - point[j][2]);
        facenormal[i][2] =
            (point[k][0] - point[j][0]) * (point[l][1] - point[j][1]) -
            (point[k][1] - point[j][1]) * (point[l][0] - point[j][0]);
            
        /* compute (2 *area)^2 for this face */
        facearea2[i] = facenormal[i][0] * facenormal[i][0] +
            facenormal[i][1] * facenormal[i][1] +
            facenormal[i][2] * facenormal[i][2];
        
        /* compute edge lengths (squared) */
        for (j = i + 1; j < 4; j++) {
            dx = point[i][0] - point[j][0];
            dy = point[i][1] - point[j][1];
            dz = point[i][2] - point[j][2];
            edgelength[i][j] = dx * dx + dy * dy + dz * dz;
        }
    }
    
    /* for each edge in the tetrahedron */
    for (i = 0; i < 3; i++) {
        for (j = i + 1; j < 4; j++) {
            k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
            l = 6 - i - j - k;
            
            /* compute the expression for minimum sine, squared, over 4 
               The reason it's over 4 is because the area values we have
               are actually twice the area squared */
            /* if either face area is zero, the sine is zero */
            if (facearea2[k] > 0 && facearea2[l] > 0)
            {
                sine2 = edgelength[i][j] / (facearea2[k] * facearea2[l]);
            }
            else
            {
                if (improvebehave.verbosity > 5) 
                {
                    printf("Encountered zero-area face.\n");
                    printf("Here is the tet (%d %d %d %d):\n", (int) vtx1, (int) vtx2, (int) vtx3, (int) vtx4);
                    printf(",\n");
                }
                sine2 = 0.0;
            }
            
            /* accumulate sine */
            sinesum += sqrt(sine2);
        }
    }
    
    /* average sine */
    return (sinesum / 6.0) * pyrvolume;
}

/* compute Z, a quantity associated with circumradius computation
   TODO this code is lifted from Jonathan's tetcircumcenter computation
   in primitives.c */
starreal getZ(starreal *tetorg,
              starreal *tetdest,
              starreal *tetfapex,
              starreal *tettapex)
{
    starreal xot, yot, zot, xdt, ydt, zdt, xft, yft, zft;
    starreal otlength, dtlength, ftlength;
    starreal xcrossdf, ycrossdf, zcrossdf;
    starreal xcrossfo, ycrossfo, zcrossfo;
    starreal xcrossod, ycrossod, zcrossod;
    starreal xct, yct, zct;

    /* Use coordinates relative to the apex of the tetrahedron. */
    xot = tetorg[0] - tettapex[0];
    yot = tetorg[1] - tettapex[1];
    zot = tetorg[2] - tettapex[2];
    xdt = tetdest[0] - tettapex[0];
    ydt = tetdest[1] - tettapex[1];
    zdt = tetdest[2] - tettapex[2];
    xft = tetfapex[0] - tettapex[0];
    yft = tetfapex[1] - tettapex[1];
    zft = tetfapex[2] - tettapex[2];
    /* Squares of lengths of the origin, destination, and face apex edges. */
    otlength = xot * xot + yot * yot + zot * zot;
    dtlength = xdt * xdt + ydt * ydt + zdt * zdt;
    ftlength = xft * xft + yft * yft + zft * zft;
    /* Cross products of the origin, destination, and face apex vectors. */
    xcrossdf = ydt * zft - yft * zdt;
    ycrossdf = zdt * xft - zft * xdt;
    zcrossdf = xdt * yft - xft * ydt;
    xcrossfo = yft * zot - yot * zft;
    ycrossfo = zft * xot - zot * xft;
    zcrossfo = xft * yot - xot * yft;
    xcrossod = yot * zdt - ydt * zot;
    ycrossod = zot * xdt - zdt * xot;
    zcrossod = xot * ydt - xdt * yot;
    
    /* Calculate offset (from apex) of circumcenter. */
    xct = (otlength * xcrossdf + dtlength * xcrossfo + ftlength * xcrossod);
    yct = (otlength * ycrossdf + dtlength * ycrossfo + ftlength * ycrossod);
    zct = (otlength * zcrossdf + dtlength * zcrossfo + ftlength * zcrossod);
        
    /* Calculate the length of this vector, which is Z */
    return sqrt(xct * xct + yct * yct + zct * zct);
}

/* the inradius to circumradius ratio */
starreal radiusratio(struct tetcomplex *mesh,
                     tag vtx1,
                     tag vtx2,
                     tag vtx3,
                     tag vtx4)
{
    starreal point[4][3];      /* the vertices of the tet */
    starreal facenormal[4][3]; /* the normals of each face of the tet */
    starreal facearea2[4];     /* areas of the faces of the tet */
    starreal pyrvolume;        /* volume of tetrahedron */
    starreal Z;                /* quantity needed for circumradius */
    starreal facesum=0.0;       /* sum of the areas of the faces */
    int i, j, k, l;          /* loop indices */
    starreal sign;
    starreal qual;
    starreal E[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
    
    /* get tet vertices */
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx1))->coord, point[0]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx2))->coord, point[1]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx3))->coord, point[2]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx4))->coord, point[3]);
    
    /* if anisotropic meshing is enabled, warp the points according the
       deformation tensor at their barycenter */
    if (improvebehave.anisotropic)
    {
        /* fetch the deformation tensor at the barycenter of this tet */
        tettensor(mesh, vtx1, vtx2, vtx3, vtx4, E);
        
        /* transform each vertex */
        for (i=0; i<4; i++)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("in radiusratio transforming point (%g %g %g) ->", point[i][0], point[i][1], point[i][2]);
            }
            
            tensortransform(point[i], point[i], E);
            
            if (improvebehave.verbosity > 5)
            {
                printf(" (%g %g %g)\n", point[i][0], point[i][1], point[i][2]);
            }
        }
    }
    
    /* calculate the volume*6 of the tetrahedron */
    pyrvolume = (starreal) orient3d(&behave, point[0], point[1], point[2], point[3]);
    
    /* if the volume is zero, the quality is zero, no reason to continue */
    if (pyrvolume == 0.0)
    {
        return 0.0;
    }
    
    /* for each vertex/face of the tetrahedron */
    for (i = 0; i < 4; i++) {
        j = (i + 1) & 3;
        if ((i & 1) == 0) {
            k = (i + 3) & 3;
            l = (i + 2) & 3;
        } else {
            k = (i + 2) & 3;
            l = (i + 3) & 3;
        }
        
        /* compute the normal for each face */
        facenormal[i][0] =
            (point[k][1] - point[j][1]) * (point[l][2] - point[j][2]) -
            (point[k][2] - point[j][2]) * (point[l][1] - point[j][1]);
        facenormal[i][1] =
            (point[k][2] - point[j][2]) * (point[l][0] - point[j][0]) -
            (point[k][0] - point[j][0]) * (point[l][2] - point[j][2]);
        facenormal[i][2] =
            (point[k][0] - point[j][0]) * (point[l][1] - point[j][1]) -
            (point[k][1] - point[j][1]) * (point[l][0] - point[j][0]);
            
        /* compute (2 *area)^2 for this face */
        facearea2[i] = facenormal[i][0] * facenormal[i][0] +
            facenormal[i][1] * facenormal[i][1] +
            facenormal[i][2] * facenormal[i][2];
        facesum += sqrt(facearea2[i]) * 0.5;
    }
    
    /* compute Z */
    Z = getZ(point[0], point[1], point[2], point[3]);
    
    /* now we are ready to compute the radius ratio, which is
    
       (108 * V^2) / Z (A1 + A2 + A3 + A4)
    
       (use 3 instead of 108 because pyrvolume = 6V)
    */
    /* use sqrt for now... */
    sign = (pyrvolume < 0.0) ? -1.0 : 1.0;
    
    qual = sign * sqrt((3.0 * pyrvolume * pyrvolume) / (Z * facesum));
    
    if (improvebehave.verbosity > 6)
    {
        printf("the volume of this tet is %g\n", pyrvolume);
        
        if (qual > 0.0 && pyrvolume < 0.0)
        {
            printf("aha! volume is negative but qual is positive!\n");
            printf("here is the tet:\n");
            printtetvertssep(mesh, vtx1, vtx2, vtx3, vtx4);
            starexit(1);
        }
    }
    
    return qual;
}

/* compute the ratio of the tet volume to the cube of
   the rms edge length */
starreal vlrms3ratio(struct tetcomplex *mesh,
                   tag vtx1,
                   tag vtx2,
                   tag vtx3,
                   tag vtx4)
{
    starreal point[4][3];      /* the vertices of the tet */
    starreal edgelength[3][4]; /* the lengths of each of the edges of the tet */
    starreal dx, dy, dz;       /* intermediate values of edge lengths */
    starreal pyrvolume;        /* volume of tetrahedron */
    int i, j, k, l;          /* loop indices */
    starreal edgelengthsum = 0.0;
    starreal lrms;             /* root mean squared of edge length */
    starreal qual;
    starreal E[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
    
    /* get tet vertices */
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx1))->coord, point[0]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx2))->coord, point[1]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx3))->coord, point[2]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vtx4))->coord, point[3]);
    
    /* if anisotropic meshing is enabled, warp the points according the
       deformation tensor at their barycenter */
    if (improvebehave.anisotropic)
    {
        /* fetch the deformation tensor at the barycenter of this tet */
        tettensor(mesh, vtx1, vtx2, vtx3, vtx4, E);
        
        /* transform each vertex */
        for (i=0; i<4; i++)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("in vlrms3 transforming point (%g %g %g) ->", point[i][0], point[i][1], point[i][2]);
            }
            
            tensortransform(point[i], point[i], E);
            
            if (improvebehave.verbosity > 5)
            {
                printf(" (%g %g %g)\n", point[i][0], point[i][1], point[i][2]);
            }
        }
    }
    
    /* calculate the volume*6 of the tetrahedron */
    pyrvolume = (starreal) orient3d(&behave, point[0], point[1], point[2], point[3]);
    
    /* if the volume is zero, the quality is zero, no reason to continue */
    if (pyrvolume == 0.0)
    {
        return 0.0;
    }
    
    /* for each vertex/face of the tetrahedron */
    for (i = 0; i < 4; i++) {
        j = (i + 1) & 3;
        if ((i & 1) == 0) {
            k = (i + 3) & 3;
            l = (i + 2) & 3;
        } else {
            k = (i + 2) & 3;
            l = (i + 3) & 3;
        }
        
        /* compute edge lengths (squared) */
        for (j = i + 1; j < 4; j++) {
            dx = point[i][0] - point[j][0];
            dy = point[i][1] - point[j][1];
            dz = point[i][2] - point[j][2];
            edgelength[i][j] = dx * dx + dy * dy + dz * dz;
        }
    }
    
    /* for each edge in the tetrahedron */
    for (i = 0; i < 3; i++) {
        for (j = i + 1; j < 4; j++) {
            k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
            l = 6 - i - j - k;
            
            edgelengthsum += edgelength[i][j];
        }
    }
    
    /* compute the root mean square */
    lrms = sqrt((1.0 / 6.0) * edgelengthsum);
    
    /* compute the normalized ratio of volume to lrms^3 */
    qual = (sqrt(2.0) * pyrvolume) / (lrms * lrms * lrms);
    
    return qual;
}

/* harness function for all quality measures */
starreal tetquality(struct tetcomplex *mesh, 
                  tag vtx1, 
                  tag vtx2,
                  tag vtx3,
                  tag vtx4,
                  int measure)
{
    starreal quality = 0.0; /* the quality of this tetrahedron */
    
    switch (measure)
    {
        case QUALMINSINE:
            quality = minsine(mesh, vtx1, vtx2, vtx3, vtx4);
            break;
        case QUALMEANSINE:
            quality = meansine(mesh, vtx1, vtx2, vtx3, vtx4);
            break;
        case QUALMINSINEANDEDGERATIO:
            quality = minsineandedgeratio(mesh, vtx1, vtx2, vtx3, vtx4);
            break;
        case QUALRADIUSRATIO:
            quality = radiusratio(mesh, vtx1, vtx2, vtx3, vtx4);
            break;
        case QUALVLRMS3RATIO:
            quality = vlrms3ratio(mesh, vtx1, vtx2, vtx3, vtx4);
            break;
        case QUALWARPEDMINSINE:
            quality = warpedminsine(mesh, vtx1, vtx2, vtx3, vtx4);
            break;
        case QUALMINANGLE:
            quality = minmaxangle(mesh, vtx1, vtx2, vtx3, vtx4, false);
            break;
        case QUALMAXANGLE:
            quality = minmaxangle(mesh, vtx1, vtx2, vtx3, vtx4, true);
            break;
        default:
            printf("I don't know what quality measure %d is. Dying...\n", measure);
            starexit(1);
    }
    
    return quality;
}


/********* Statistics printing routines begin here                   *********/
/**                                                                         **/
/**                                                                         **/

void statisticsqualitystream(FILE *o,
                             struct behavior *behave,
                             struct tetcomplex *plex,
                             bool anisotropic)
{
#define BINS 90                                         /* Must be even!!! */
#define RATIOBINS 100

  struct tetcomplexposition position;
  tag tet[4];
  starreal point[4][3];
  starreal tcenter[3];
  starreal tansquaretable[8];
  starreal tansquaretable2[BINS / 2 - 1];
  starreal aspecttable[16];
  starreal circumtable[16];
  starreal edgelength[3][4];
  starreal facenormal[4][3];
  starreal dx, dy, dz;
  starreal dotproduct;
  starreal tansquare;
  starreal pyrvolume;
  starreal facearea2;
  starreal pyrbiggestface2;
  starreal shortest, longest;
  starreal pyrshortest2, pyrlongest2;
  starreal smallestvolume, biggestvolume;
  starreal pyrminaltitude2;
  starreal minaltitude;
  starreal pyraspect2;
  starreal worstaspect;
  starreal pyrcircumratio2;
  starreal worstcircumratio;
  starreal smallestangle, biggestangle;
  starreal radconst, degconst;
  arraypoolulong anglecount[18];
  arraypoolulong anglecount2[BINS];
  arraypoolulong rnrrratiocount[RATIOBINS];
  arraypoolulong vlrms3ratiocount[RATIOBINS];
  arraypoolulong aspectcount[16];
  arraypoolulong circumcount[16];
  int aspectindex;
  int circumindex;
  int tendegree;
  int bindegree;
  int acutebiggestflag;
  int firstiterationflag;
  int i, ii, j, k, l;
  starreal rnrrratioqual, vlrms3ratioqual;
  int rnrrwhichbin, vlrms3whichbin;
  starreal rnrrsmallestratio = HUGEFLOAT;
  starreal vlrms3smallestratio = HUGEFLOAT;
  starreal rnrrlargestratio = 0.0;
  starreal vlrms3largestratio = 0.0;
  starreal E[3][3];
  
  starreal worstqual = HUGEFLOAT;
  starreal thisqual;
  
  radconst = PI / 18.0;
  degconst = 180.0 / PI;
  for (i = 0; i < 8; i++) {
    tansquaretable[i] = tan(radconst * (starreal) (i + 1));
    tansquaretable[i] = tansquaretable[i] * tansquaretable[i];
  }
  radconst = PI / (starreal) BINS;
  for (i = 0; i < BINS / 2 - 1; i++) {
    tansquaretable2[i] = tan(radconst * (starreal) (i + 1));
    tansquaretable2[i] = tansquaretable2[i] * tansquaretable2[i] - 0.00000001;
  }
  for (i = 0; i < 18; i++) {
    anglecount[i] = 0;
  }
  for (i = 0; i < BINS; i++) {
    anglecount2[i] = 0;
  }
  for (i = 0; i < RATIOBINS; i++)
  {
      rnrrratiocount[i] = 0;
      vlrms3ratiocount[i] = 0;
  }

  aspecttable[0]  =      1.5;      aspecttable[1]  =     2.0;
  aspecttable[2]  =      2.5;      aspecttable[3]  =     3.0;
  aspecttable[4]  =      4.0;      aspecttable[5]  =     6.0;
  aspecttable[6]  =     10.0;      aspecttable[7]  =    15.0;
  aspecttable[8]  =     25.0;      aspecttable[9]  =    50.0;
  aspecttable[10] =    100.0;      aspecttable[11] =   300.0;
  aspecttable[12] =   1000.0;      aspecttable[13] = 10000.0;
  aspecttable[14] = 100000.0;      aspecttable[15] =     0.0;
  for (i = 0; i < 16; i++) {
    aspectcount[i] = 0;
  }

  circumtable[0]  =      0.75;     circumtable[1]  =     1.0;
  circumtable[2]  =      1.5;      circumtable[3]  =     2.0;
  circumtable[4]  =      3.0;      circumtable[5]  =     5.0;
  circumtable[6]  =     10.0;      circumtable[7]  =    15.0;
  circumtable[8]  =     25.0;      circumtable[9]  =    50.0;
  circumtable[10] =    100.0;      circumtable[11] =   300.0;
  circumtable[12] =   1000.0;      circumtable[13] = 10000.0;
  circumtable[14] = 100000.0;      circumtable[15] =     0.0;
  for (i = 0; i < 16; i++) {
    circumcount[i] = 0;
  }

  shortest = 0.0;
  longest = 0.0;
  smallestvolume = 0.0;
  biggestvolume = 0.0;
  minaltitude = 0.0;
  worstaspect = 0.0;
  worstcircumratio = 0.0;
  smallestangle = 100.0;
  biggestangle = 0.0;
  acutebiggestflag = 1;

  firstiterationflag = 1;
  tetcomplexiteratorinit(plex, &position);
  tetcomplexiteratenoghosts(&position, tet);
  while (tet[0] != STOP) {
    
    /* ratio bin stuff */
    rnrrratioqual = tetquality(plex, tet[0], tet[1], tet[2], tet[3], QUALRADIUSRATIO);
    vlrms3ratioqual = tetquality(plex, tet[0], tet[1], tet[2], tet[3], QUALVLRMS3RATIO);
    rnrrratioqual = rnrrratioqual * rnrrratioqual;
    
    if (rnrrratioqual > rnrrlargestratio) rnrrlargestratio = rnrrratioqual;
    if (rnrrratioqual < rnrrsmallestratio) rnrrsmallestratio = rnrrratioqual;
    if (vlrms3ratioqual > vlrms3largestratio) vlrms3largestratio = vlrms3ratioqual;
    if (vlrms3ratioqual < vlrms3smallestratio) vlrms3smallestratio = vlrms3ratioqual;
    rnrrwhichbin = (int) (((starreal) RATIOBINS) * rnrrratioqual);
    vlrms3whichbin = (int) (((starreal) RATIOBINS) * vlrms3ratioqual);
    assert(rnrrwhichbin <= RATIOBINS);
    rnrrratiocount[rnrrwhichbin]++;
    assert(vlrms3whichbin <= RATIOBINS);
    vlrms3ratiocount[vlrms3whichbin]++;
     
    vcopy(((struct vertex *) tetcomplextag2vertex(plex, tet[0]))->coord, point[0]);
    vcopy(((struct vertex *) tetcomplextag2vertex(plex, tet[1]))->coord, point[1]);
    vcopy(((struct vertex *) tetcomplextag2vertex(plex, tet[2]))->coord, point[2]);
    vcopy(((struct vertex *) tetcomplextag2vertex(plex, tet[3]))->coord, point[3]);
    
    /* if anisotropic meshing is enabled, warp the points according the
       deformation tensor at their barycenter */
    if (anisotropic)
    {
        /* fetch the deformation tensor at the barycenter of this tet */
        tettensor(plex, tet[0], tet[1], tet[2], tet[3], E);
        
        /* transform each vertex */
        for (i=0; i<4; i++)
        {
            tensortransform(point[i], point[i], E);
        }
    }
    
    /* compute quality */
    thisqual = tetquality(plex, tet[0], tet[1], tet[2], tet[3], improvebehave.qualmeasure);
    if (thisqual < worstqual) worstqual = thisqual;
    
    pyrshortest2 = 0.0;
    pyrlongest2 = 0.0;
    pyrbiggestface2 = 0.0;

    for (i = 0; i < 4; i++) {
      j = (i + 1) & 3;
      if ((i & 1) == 0) {
        k = (i + 3) & 3;
        l = (i + 2) & 3;
      } else {
        k = (i + 2) & 3;
        l = (i + 3) & 3;
      }

      facenormal[i][0] =
        (point[k][1] - point[j][1]) * (point[l][2] - point[j][2]) -
        (point[k][2] - point[j][2]) * (point[l][1] - point[j][1]);
      facenormal[i][1] =
        (point[k][2] - point[j][2]) * (point[l][0] - point[j][0]) -
        (point[k][0] - point[j][0]) * (point[l][2] - point[j][2]);
      facenormal[i][2] =
        (point[k][0] - point[j][0]) * (point[l][1] - point[j][1]) -
        (point[k][1] - point[j][1]) * (point[l][0] - point[j][0]);
      facearea2 = facenormal[i][0] * facenormal[i][0] +
                  facenormal[i][1] * facenormal[i][1] +
                  facenormal[i][2] * facenormal[i][2];
      if (facearea2 > pyrbiggestface2) {
        pyrbiggestface2 = facearea2;
      }

      for (j = i + 1; j < 4; j++) {
        dx = point[i][0] - point[j][0];
        dy = point[i][1] - point[j][1];
        dz = point[i][2] - point[j][2];
        edgelength[i][j] = dx * dx + dy * dy + dz * dz;
        if (edgelength[i][j] > pyrlongest2) {
          pyrlongest2 = edgelength[i][j];
        }
        if ((j == 1) || (edgelength[i][j] < pyrshortest2)) {
          pyrshortest2 = edgelength[i][j];
        }
      }
    }
    if (pyrlongest2 > longest) {
      longest = pyrlongest2;
    }
    if ((pyrshortest2 < shortest) || firstiterationflag) {
      shortest = pyrshortest2;
    }

    pyrvolume = (starreal)
      orient3d(behave, point[0], point[1], point[2], point[3]);
    if ((pyrvolume < smallestvolume) || firstiterationflag) {
      smallestvolume = pyrvolume;
    }
    if (pyrvolume > biggestvolume) {
      biggestvolume = pyrvolume;
    }
    pyrminaltitude2 = pyrvolume * pyrvolume / pyrbiggestface2;
    if ((pyrminaltitude2 < minaltitude) || firstiterationflag) {
      minaltitude = pyrminaltitude2;
    }
    pyraspect2 = pyrlongest2 / pyrminaltitude2;
    if (pyraspect2 > worstaspect) {
      worstaspect = pyraspect2;
    }
    aspectindex = 0;
    while ((pyraspect2 >
            aspecttable[aspectindex] * aspecttable[aspectindex]) &&
           (aspectindex < 15)) {
      aspectindex++;
    }
    aspectcount[aspectindex]++;

    tetcircumcenter(behave, point[0], point[1], point[2], point[3], tcenter,
                    (starreal *) NULL, (starreal *) NULL, (starreal *) NULL);
    pyrcircumratio2 = (tcenter[0] * tcenter[0] + tcenter[1] * tcenter[1] +
                       tcenter[2] * tcenter[2]) / pyrshortest2;
    if (pyrcircumratio2 > worstcircumratio) {
      worstcircumratio = pyrcircumratio2;
    }
    circumindex = 0;
    while ((pyrcircumratio2 >
            circumtable[circumindex] * circumtable[circumindex]) &&
           (circumindex < 15)) {
      circumindex++;
    }
    circumcount[circumindex]++;

    for (i = 0; i < 3; i++) {
      for (j = i + 1; j < 4; j++) {
        k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
        l = 6 - i - j - k;
        
        dotproduct = facenormal[i][0] * facenormal[j][0] +
                     facenormal[i][1] * facenormal[j][1] +
                     facenormal[i][2] * facenormal[j][2];
        if (dotproduct == 0.0) {
          anglecount[9]++;
          anglecount2[BINS / 2]++;
          if (acutebiggestflag) {
            biggestangle = 1.0e+300;
            acutebiggestflag = 0;
          }
        } else {
          tansquare = pyrvolume * pyrvolume * edgelength[k][l] /
                      (dotproduct * dotproduct);
          tendegree = 8;
          bindegree = BINS / 2 - 1;
          for (ii = 7; ii >= 0; ii--) {
            if (tansquare < tansquaretable[ii]) {
              tendegree = ii;
            }
          }
          for (ii = BINS / 2 - 2; ii >= 0; ii--) {
            if (tansquare < tansquaretable2[ii]) {
              bindegree = ii;
            }
          }
          if (dotproduct < 0.0) {
            anglecount[tendegree]++;
            if (tansquare > 100000000.0) {
              bindegree = BINS / 2;
            }
            anglecount2[bindegree]++;
            if (tansquare < smallestangle) {
              smallestangle = tansquare;
            }
            if (acutebiggestflag && (tansquare > biggestangle)) {
              biggestangle = tansquare;
            }
          } else {
            anglecount[17 - tendegree]++;
            anglecount2[BINS - 1 - bindegree]++;
            if (acutebiggestflag || (tansquare < biggestangle)) {
              biggestangle = tansquare;
              acutebiggestflag = 0;
            }
          }
        }
      }
    }

    tetcomplexiteratenoghosts(&position, tet);
    firstiterationflag = 0;
  }

  shortest = sqrt(shortest);
  longest = sqrt(longest);
  minaltitude = sqrt(minaltitude);
  worstaspect = sqrt(worstaspect);
  worstcircumratio = sqrt(worstcircumratio);
  smallestvolume /= 6.0;
  biggestvolume /= 6.0;
  smallestangle = degconst * atan(sqrt(smallestangle));
  if (acutebiggestflag) {
    biggestangle = degconst * atan(sqrt(biggestangle));
  } else {
    biggestangle = 180.0 - degconst * atan(sqrt(biggestangle));
  }
  
  if (anisotropic)
  {
      fprintf(o,"Mesh quality statistics (ISOTROPIC SPACE)\n\n");
  }
  else
  {
      fprintf(o,"Mesh quality statistics (PHYSICAL SPACE)\n\n");
  }
  
  fprintf(o,"  Smallest volume: %14.5g   |  Largest volume: %14.5g\n",
         smallestvolume, biggestvolume);
  fprintf(o,"  Shortest edge: %16.5g   |  Longest edge: %16.5g\n",
         shortest, longest);
  fprintf(o,"  Shortest altitude: %12.5g   |  Largest aspect ratio: %8.5g\n\n",
         minaltitude, worstaspect);

  fprintf(o,"  Tetrahedron aspect ratio histogram:\n");
  fprintf(o,"  1.2247 - %-6.6g    :   %8lu   | %6.6g - %-6.6g     :  %8lu\n",
         aspecttable[0], (unsigned long) aspectcount[0],
         aspecttable[7], aspecttable[8], (unsigned long) aspectcount[8]);
  for (i = 1; i < 7; i++) {
    fprintf(o,"  %6.6g - %-6.6g    :   %8lu   | %6.6g - %-6.6g     :  %8lu\n",
           aspecttable[i - 1], aspecttable[i], (unsigned long) aspectcount[i],
           aspecttable[i + 7], aspecttable[i + 8],
           (unsigned long) aspectcount[i + 8]);
  }
  fprintf(o,"  %6.6g - %-6.6g    :   %8lu   | %6.6g -            :  %8lu\n",
         aspecttable[6], aspecttable[7], (unsigned long) aspectcount[7],
         aspecttable[14], (unsigned long) aspectcount[15]);
  fprintf(o,"  (Aspect ratio is longest edge divided by shortest altitude)\n");

  fprintf(o,"\n  Largest circumradius-to-shortest-edge ratio: %22.5g\n\n",
         worstcircumratio);

  fprintf(o,"  Tetrahedron circumradius-to-shortest-edge ratio histogram:\n");
  fprintf(o,"  0.6123 - %-6.6g    :   %8lu   | %6.6g - %-6.6g     :  %8lu\n",
         circumtable[0], (unsigned long) circumcount[0],
         circumtable[7], circumtable[8], (unsigned long) circumcount[8]);
  for (i = 1; i < 7; i++) {
    fprintf(o,"  %6.6g - %-6.6g    :   %8lu   | %6.6g - %-6.6g     :  %8lu\n",
           circumtable[i - 1], circumtable[i], (unsigned long) circumcount[i],
           circumtable[i + 7], circumtable[i + 8],
           (unsigned long) circumcount[i + 8]);
  }
  fprintf(o,"  %6.6g - %-6.6g    :   %8lu   | %6.6g -            :  %8lu\n",
         circumtable[6], circumtable[7], (unsigned long) circumcount[7],
         circumtable[14], (unsigned long) circumcount[15]);

  fprintf(o,"\n  Smallest dihedral: %12.5g   |  Largest dihedral: %12.5g\n\n",
         smallestangle, biggestangle);

  fprintf(o,"  Dihedral angle histogram:\n");
  for (i = 0; i < 9; i++) {
    fprintf(o,"      %2d - %2d degrees:   %8lu   |    %3d - %3d degrees:  %8lu\n",
           i * 10, i * 10 + 10, (unsigned long) anglecount[i],
           i * 10 + 90, i * 10 + 100, (unsigned long) anglecount[i + 9]);
  }
  fprintf(o,"\n");

  fprintf(o,"  For a histogram, input the following line to hist.c:\n  ");
  for (i = 0; i < BINS; i++) {
    fprintf(o,"%lu ", anglecount2[i]);
  }
  fprintf(o,"%12.7g %12.7g\n\n", smallestangle, biggestangle);
  
  fprintf(o,"  For a rnrrratio histogram, input the following line to hist.c:\n  ");
  for (i = 0; i < RATIOBINS; i++) {
    fprintf(o,"%lu ", rnrrratiocount[i]);
  }
  fprintf(o,"%12.7g %12.7g\n\n", rnrrsmallestratio, rnrrlargestratio);
  
  fprintf(o,"  For a vlrms3ratio histogram, input the following line to hist.c:\n  ");
  for (i = 0; i < RATIOBINS; i++) {
    fprintf(o,"%lu ", vlrms3ratiocount[i]);
  }
  fprintf(o,"%12.7g %12.7g\n\n", vlrms3smallestratio, vlrms3largestratio);
  
  fprintf(o, "worstqual: %12.7g\n\n", worstqual);
}

void improvestatistics(struct behavior *behave,
                       struct tetcomplex *plex,
                       bool anisotropic)
{
    statisticsqualitystream(stdout, behave, plex, anisotropic);
}

void getextremeangles(struct behavior *behave,
                      struct tetcomplex *plex,
                      starreal *outsmallestangle,
                      starreal *outbiggestangle)
{
  struct tetcomplexposition position;
  tag tet[4];
  starreal point[4][3];
  starreal tcenter[3];
  starreal tansquaretable[8];
  starreal aspecttable[16];
  starreal circumtable[16];
  starreal edgelength[3][4];
  starreal facenormal[4][3];
  starreal dx, dy, dz;
  starreal dotproduct;
  starreal tansquare;
  starreal pyrvolume;
  starreal facearea2;
  starreal pyrbiggestface2;
  starreal shortest, longest;
  starreal pyrshortest2, pyrlongest2;
  starreal smallestvolume, biggestvolume;
  starreal pyrminaltitude2;
  starreal minaltitude;
  starreal pyraspect2;
  starreal worstaspect;
  starreal pyrcircumratio2;
  starreal worstcircumratio;
  starreal smallestangle, biggestangle;
  starreal radconst, degconst;
  arraypoolulong anglecount[18];
  arraypoolulong aspectcount[16];
  arraypoolulong circumcount[16];
  int aspectindex;
  int circumindex;
  int tendegree;
  int acutebiggestflag;
  int firstiterationflag;
  int i, ii, j, k, l;
  starreal E[3][3];

  radconst = PI / 18.0;
  degconst = 180.0 / PI;
  for (i = 0; i < 8; i++) {
    tansquaretable[i] = tan(radconst * (starreal) (i + 1));
    tansquaretable[i] = tansquaretable[i] * tansquaretable[i];
  }
  for (i = 0; i < 18; i++) {
    anglecount[i] = 0;
  }

  aspecttable[0]  =      1.5;      aspecttable[1]  =     2.0;
  aspecttable[2]  =      2.5;      aspecttable[3]  =     3.0;
  aspecttable[4]  =      4.0;      aspecttable[5]  =     6.0;
  aspecttable[6]  =     10.0;      aspecttable[7]  =    15.0;
  aspecttable[8]  =     25.0;      aspecttable[9]  =    50.0;
  aspecttable[10] =    100.0;      aspecttable[11] =   300.0;
  aspecttable[12] =   1000.0;      aspecttable[13] = 10000.0;
  aspecttable[14] = 100000.0;      aspecttable[15] =     0.0;
  for (i = 0; i < 16; i++) {
    aspectcount[i] = 0;
  }

  circumtable[0]  =      0.75;     circumtable[1]  =     1.0;
  circumtable[2]  =      1.5;      circumtable[3]  =     2.0;
  circumtable[4]  =      3.0;      circumtable[5]  =     5.0;
  circumtable[6]  =     10.0;      circumtable[7]  =    15.0;
  circumtable[8]  =     25.0;      circumtable[9]  =    50.0;
  circumtable[10] =    100.0;      circumtable[11] =   300.0;
  circumtable[12] =   1000.0;      circumtable[13] = 10000.0;
  circumtable[14] = 100000.0;      circumtable[15] =     0.0;
  for (i = 0; i < 16; i++) {
    circumcount[i] = 0;
  }

  shortest = 0.0;
  longest = 0.0;
  smallestvolume = 0.0;
  biggestvolume = 0.0;
  minaltitude = 0.0;
  worstaspect = 0.0;
  worstcircumratio = 0.0;
  smallestangle = 100.0;
  biggestangle = 0.0;
  acutebiggestflag = 1;

  firstiterationflag = 1;
  tetcomplexiteratorinit(plex, &position);
  tetcomplexiteratenoghosts(&position, tet);
  while (tet[0] != STOP) {
    
      vcopy(((struct vertex *) tetcomplextag2vertex(plex, tet[0]))->coord, point[0]);
      vcopy(((struct vertex *) tetcomplextag2vertex(plex, tet[1]))->coord, point[1]);
      vcopy(((struct vertex *) tetcomplextag2vertex(plex, tet[2]))->coord, point[2]);
      vcopy(((struct vertex *) tetcomplextag2vertex(plex, tet[3]))->coord, point[3]);

      /* if anisotropic meshing is enabled, warp the points according the
         deformation tensor at their barycenter */
      if (improvebehave.anisotropic)
      {
          /* fetch the deformation tensor at the barycenter of this tet */
          tettensor(plex, tet[0], tet[1], tet[2], tet[3], E);

          /* transform each vertex */
          for (i=0; i<4; i++)
          {
              tensortransform(point[i], point[i], E);
          }
      }
    pyrshortest2 = 0.0;
    pyrlongest2 = 0.0;
    pyrbiggestface2 = 0.0;

    for (i = 0; i < 4; i++) {
      j = (i + 1) & 3;
      if ((i & 1) == 0) {
        k = (i + 3) & 3;
        l = (i + 2) & 3;
      } else {
        k = (i + 2) & 3;
        l = (i + 3) & 3;
      }

      facenormal[i][0] =
        (point[k][1] - point[j][1]) * (point[l][2] - point[j][2]) -
        (point[k][2] - point[j][2]) * (point[l][1] - point[j][1]);
      facenormal[i][1] =
        (point[k][2] - point[j][2]) * (point[l][0] - point[j][0]) -
        (point[k][0] - point[j][0]) * (point[l][2] - point[j][2]);
      facenormal[i][2] =
        (point[k][0] - point[j][0]) * (point[l][1] - point[j][1]) -
        (point[k][1] - point[j][1]) * (point[l][0] - point[j][0]);
      facearea2 = facenormal[i][0] * facenormal[i][0] +
                  facenormal[i][1] * facenormal[i][1] +
                  facenormal[i][2] * facenormal[i][2];
      if (facearea2 > pyrbiggestface2) {
        pyrbiggestface2 = facearea2;
      }

      for (j = i + 1; j < 4; j++) {
        dx = point[i][0] - point[j][0];
        dy = point[i][1] - point[j][1];
        dz = point[i][2] - point[j][2];
        edgelength[i][j] = dx * dx + dy * dy + dz * dz;
        if (edgelength[i][j] > pyrlongest2) {
          pyrlongest2 = edgelength[i][j];
        }
        if ((j == 1) || (edgelength[i][j] < pyrshortest2)) {
          pyrshortest2 = edgelength[i][j];
        }
      }
    }
    if (pyrlongest2 > longest) {
      longest = pyrlongest2;
    }
    if ((pyrshortest2 < shortest) || firstiterationflag) {
      shortest = pyrshortest2;
    }

    pyrvolume = (starreal)
      orient3d(behave, point[0], point[1], point[2], point[3]);
    if ((pyrvolume < smallestvolume) || firstiterationflag) {
      smallestvolume = pyrvolume;
    }
    if (pyrvolume > biggestvolume) {
      biggestvolume = pyrvolume;
    }
    pyrminaltitude2 = pyrvolume * pyrvolume / pyrbiggestface2;
    if ((pyrminaltitude2 < minaltitude) || firstiterationflag) {
      minaltitude = pyrminaltitude2;
    }
    pyraspect2 = pyrlongest2 / pyrminaltitude2;
    if (pyraspect2 > worstaspect) {
      worstaspect = pyraspect2;
    }
    aspectindex = 0;
    while ((pyraspect2 >
            aspecttable[aspectindex] * aspecttable[aspectindex]) &&
           (aspectindex < 15)) {
      aspectindex++;
    }
    aspectcount[aspectindex]++;

    tetcircumcenter(behave, point[0], point[1], point[2], point[3], tcenter,
                    (starreal *) NULL, (starreal *) NULL, (starreal *) NULL);
    pyrcircumratio2 = (tcenter[0] * tcenter[0] + tcenter[1] * tcenter[1] +
                       tcenter[2] * tcenter[2]) / pyrshortest2;
    if (pyrcircumratio2 > worstcircumratio) {
      worstcircumratio = pyrcircumratio2;
    }
    circumindex = 0;
    while ((pyrcircumratio2 >
            circumtable[circumindex] * circumtable[circumindex]) &&
           (circumindex < 15)) {
      circumindex++;
    }
    circumcount[circumindex]++;

    for (i = 0; i < 3; i++) {
      for (j = i + 1; j < 4; j++) {
        k = (i > 0) ? 0 : (j > 1) ? 1 : 2;
        l = 6 - i - j - k;
        dotproduct = facenormal[i][0] * facenormal[j][0] +
                     facenormal[i][1] * facenormal[j][1] +
                     facenormal[i][2] * facenormal[j][2];
        if (dotproduct == 0.0) {
          anglecount[9]++;
          if (acutebiggestflag)
          {
              biggestangle = 1.0e+300;
              acutebiggestflag = 0;
          }
        } else {
          tansquare = pyrvolume * pyrvolume * edgelength[k][l] /
                      (dotproduct * dotproduct);
          tendegree = 8;
          for (ii = 7; ii >= 0; ii--) {
            if (tansquare < tansquaretable[ii]) {
              tendegree = ii;
            }
          }
          if (dotproduct < 0.0) {
            anglecount[tendegree]++;
            if (tansquare < smallestangle) {
              smallestangle = tansquare;
            }
            if (acutebiggestflag && (tansquare > biggestangle)) {
              biggestangle = tansquare;
            }
          } else {
            anglecount[17 - tendegree]++;
            if (acutebiggestflag || (tansquare < biggestangle)) {
              biggestangle = tansquare;
              acutebiggestflag = 0;
            }
          }
        }
      }
    }

    tetcomplexiteratenoghosts(&position, tet);
    firstiterationflag = 0;
  }

  shortest = sqrt(shortest);
  longest = sqrt(longest);
  minaltitude = sqrt(minaltitude);
  worstaspect = sqrt(worstaspect);
  worstcircumratio = sqrt(worstcircumratio);
  smallestvolume /= 6.0;
  biggestvolume /= 6.0;
  smallestangle = degconst * atan(sqrt(smallestangle));
  if (acutebiggestflag) {
    biggestangle = degconst * atan(sqrt(biggestangle));
  } else {
    biggestangle = 180.0 - degconst * atan(sqrt(biggestangle));
  }

  *outsmallestangle = smallestangle;
  *outbiggestangle = biggestangle;
}

void setbeginqual(struct behavior *behave,
                  struct tetcomplex *plex)
{
    starreal smallestangle = 0.0;
    starreal biggestangle = HUGEFLOAT;
    
    /* fetch the values for these angles */
    getextremeangles(behave, plex, &smallestangle, &biggestangle);
    
    stats.startminangle = smallestangle;
    stats.startmaxangle = biggestangle;
}

/* given the two vertices of a known boundary edge,
   compute the angle between it's two incident
   boundary faces */
starreal getboundaryedgeangle(struct tetcomplex *mesh,
                            tag v1,
                            tag v2,
                            tag vleft,
                            tag vright)
{
    starreal point[4][3];      /* the actual positions of the four vertices*/
    starreal E[3][3];
    starreal e[3][3];          /* edges for normal computation */
    starreal norm[2][3];       /* face normals */
    starreal edgelength;       /* length of boundary edge */
    starreal volume;           /* volume of tet formed by four vertices */
    starreal dotprod;          /* the dot product of the two inward face normals */
    starreal tantheta;         /* tangent of the angle */
    starreal angle;            /* angle we are computing */
    
    /* make sure neither of these are GHOST vertices themselves */
    assert(vleft != GHOSTVERTEX);
    assert(vright != GHOSTVERTEX);
    
    /* fetch actual vertex values */
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, v1))->coord, point[0]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, v2))->coord, point[1]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vleft))->coord, point[2]);
    vcopy(((struct vertex *) tetcomplextag2vertex(mesh, vright))->coord, point[3]);
            
    /* if anisotropic meshing is enabled, warp the points according the
       deformation tensor at their barycenter */
    if (improvebehave.anisotropic)
    {
        /* fetch the deformation tensor at the barycenter of points */
        tettensor(mesh, v1, v2, vleft, vright, E);

        /* transform each vertex */
        tensortransform(point[0], point[0], E);
        tensortransform(point[1], point[1], E);
        tensortransform(point[2], point[2], E);
        tensortransform(point[3], point[3], E);
    }
    
    /* e[0] from v1 to v2 */
    vsub(point[1], point[0], e[0]);
    /* e[1] from v1 to right */
    vsub(point[2], point[0], e[1]);
    /* e[2] from v1 to left */
    vsub(point[3], point[0], e[2]);
    
    /* compute the length of the edge in question */
    edgelength = vlength(e[0]);
    
    /* compute face normals, pointing out of the mesh interior */
    cross(e[1], e[0], norm[0]);
    cross(e[0], e[2], norm[1]);
    
    /* compute 6 * volume of the tetrahedron with these four vertices */
    volume = (starreal) orient3d(&behave, point[0], point[1], point[2], point[3]);
    
    /* find the dot product of the two vectors */
    dotprod = dot(norm[0], norm[1]);
    
    /* if the dot product is zero, then the angle is +-90 degrees */
    if (dotprod == 0)
    {
        /* if the volume is negative, angle is 270 degrees */
        angle = (volume > 0) ? PI / 2.0 : (3.0 * PI) / 2.0;
    }
    else
    {
        /* compute the tangent of the angle using the tangent formula:
    
           tan(theta_ij) = - 6 * V * l_ij
                           --------------
                            dot(n_k, n_l)
                        
           because this formula is accurate in the entire range.
        */
        tantheta = (-volume * edgelength) / dotprod;
        
        /* now compute the actual angle */
        angle = atan(tantheta);
        
        if (improvebehave.verbosity > 5)
        {
            printf("Raw arctan answer was %g, volume is %g and dotprod is %g\n", angle, volume, dotprod);
        }
        
        /* adjust angle for sign of dot product */
        if (dotprod > 0)
        {
            angle += PI;
        }
        
        /* make negative angles positive */
        if (angle < 0)
        {
            angle += 2.0 * PI;
        }
        
        if (improvebehave.verbosity > 5)
        {
            printf("Final angle found is %g radians, or %g degrees\n", angle, angle * (180.0 / PI));
        }
        
        /* zero angles must actually be 360 degrees...?? */
        if (angle == 0)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("correcting zero to 360...\n");
            }
            angle = 2.0 * PI;
        }
    }
    
    return angle;
}

/* given an input mesh, find the worst "input" angle.
   that is, find the smallest angle between two faces
   of the boundary */
starreal worstinputangle(struct tetcomplex *mesh)
{
    starreal angle;                     /* angle between two surface faces */
    starreal worstangle = 2.0 * PI;     /* worst input angle */
    starreal minqual, meanqual[NUMMEANTHRESHOLDS];         /* quality of the worst tet in the mesh */
    struct arraypoolstack tetstack;   /* stack of tets  */
    int numboundedges;                /* number of boundary edges for a tet */
    tag edgelist[6][2];               /* list of boundary edges for a tet */
    tag edgefaces[6][2];
    struct improvetet * stacktet;     /* tet we're pulling off the stack */
    int i;
    
    stackinit(&tetstack, sizeof(struct improvetet));
    
    /* fill the stack of tets with all tets in the mesh */
    fillstackqual(mesh, &tetstack, improvebehave.qualmeasure, HUGEFLOAT, meanqual, &minqual);
    
    /* go through each tet on the stack */
    while (tetstack.top != STACKEMPTY)
    {
        /* pull the top tet off the stack */
        stacktet = (struct improvetet *) stackpop(&tetstack);
        
        /* check for any boundary edges */
        numboundedges = boundedges(mesh,
                                   stacktet->verts[0], 
                                   stacktet->verts[1], 
                                   stacktet->verts[2], 
                                   stacktet->verts[3],
                                   edgelist,
                                   edgefaces,
                                   NULL,
                                   NULL);
        
        if (numboundedges != 0)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("tet (%d %d %d %d) has %d bound edges:\n", (int) stacktet->verts[0], 
                                                                  (int) stacktet->verts[1], 
                                                                  (int) stacktet->verts[2], 
                                                                  (int) stacktet->verts[3],
                                                                  numboundedges);
            }
            /* for each boundary edge */
            for (i=0; i<numboundedges; i++)
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("testing boundary edge (%d, %d)\n", (int) edgelist[i][0], (int) edgelist[i][1]);
                }
                
                /* compute the angle between the boundary faces */
                angle = getboundaryedgeangle(mesh, edgelist[i][0], edgelist[i][1], edgefaces[i][0], edgefaces[i][1]);
            
                /* if this angle is smaller than what we've seen, update */
                if (angle < worstangle)
                {
                    if (improvebehave.verbosity > 5)
                    {
                        printf("New worst angle of %g radians (%g degrees) found\n", angle, angle * (180.0 / PI));
                    }
                    worstangle = angle;
                }
            }
        }
    }
    
    /* free the stack of tets */
    stackdeinit(&tetstack);
    
    return worstangle; 
}

/* gather some information about the worst tets in the mesh */
/* according to the given quality measure, report information
   about all the tets within degreesfromworst of the worst tet */
void worsttetreport(struct tetcomplex *mesh,
                    int qualmeasure,
                    starreal degreesfromworst)
{
    starreal minqual, meanqual[NUMMEANTHRESHOLDS];            /* quality of the worst tet in the mesh */
    struct arraypoolstack tetstack;      /* stack of tets  */
    struct improvetet *stacktet;         /* current tet */
    starreal threshold;                    /* tets worse than this will be investigated */  
    int numbadtets=0;                    /* number of naughty tets */
    int numboundverts;                   /* number of boundary verts in the current tet */
    int numboundedges;
    int numboundfaces;
    int boundvertshist[5] = {0,0,0,0,0}; /* histogram of the number of boundary vertices */
    int boundfaceshist[5] = {0,0,0,0,0};
    int boundedgeshist[7] = {0,0,0,0,0,0,0};
    tag boundtags[4];                   /* boundary verts of a particular tet */
    bool bfaces;
    tag boundfacetags[4][3];
    tag boundedgetags[6][2];
    tag boundedgefaces[6][2];
    int i;
    int nbvworst=0, nbeworst=0, nbfworst=0;
    starreal worstseen = 100.0;
    tag worstverts[4] = {0,0,0,0};
    
    /* initialize the tet stack */
    stackinit(&tetstack, sizeof(struct improvetet));
    
    /* fill the stack of tets with all tets in the mesh */
    fillstackqual(mesh, &tetstack, qualmeasure, HUGEFLOAT, meanqual, &minqual);
    
    /* set the threshold below which we'll investigate this tet */
    threshold = minqual + sin(degreesfromworst * (PI / 180.0));
    
    /* now go through the stack collecting information */
    while (tetstack.top != STACKEMPTY)
    {
        /* pull the top tet off the stack */
        stacktet = (struct improvetet *) stackpop(&tetstack);
        
        /* don't go any further if this tet isn't one of the worst */
        if (stacktet->quality > threshold) continue;
        
        numbadtets++;
        
        /* fetch the number of boundary vertices for this tet */
        numboundverts = boundverts(mesh, 
                                   stacktet->verts[0],
                                   stacktet->verts[1],
                                   stacktet->verts[2],
                                   stacktet->verts[3],
                                   boundtags);
                                   
        numboundedges = boundedges(mesh, 
                                   stacktet->verts[0],
                                   stacktet->verts[1],
                                   stacktet->verts[2],
                                   stacktet->verts[3],
                                   boundedgetags,
                                   boundedgefaces,
                                   NULL,
                                   NULL);
                                  
        bfaces = boundfaces(mesh,
                            stacktet->verts[0],
                            stacktet->verts[1],
                            stacktet->verts[2],
                            stacktet->verts[3],
                            boundfacetags,
                            &numboundfaces);
                            
        if (stacktet->quality <= worstseen)
        {
            worstseen = stacktet->quality;
            worstverts[0] = stacktet->verts[0];
            worstverts[1] = stacktet->verts[1];
            worstverts[2] = stacktet->verts[2];
            worstverts[3] = stacktet->verts[3]; 
            nbvworst = numboundverts;
            nbeworst = numboundedges;
            nbfworst = numboundfaces;
        }
                                   
        boundvertshist[numboundverts]++;
        boundedgeshist[numboundedges]++;
        boundfaceshist[numboundfaces]++;
    }
    
    /* free the stack of tets */
    stackdeinit(&tetstack);
    
    /* print report */
    printf("\nWorst tet report:\n");
    printf("    Worst overall quality: %g\n", pq(minqual));
    printf("    Worst tet (%d, %d, %d, %d) had %d vertices, %d edges, and %d faces on boundary.\n",
                                                                            (int) worstverts[0],
                                                                            (int) worstverts[1],
                                                                            (int) worstverts[2],
                                                                            (int) worstverts[3],
                                                                            nbvworst,
                                                                            nbeworst,
                                                                            nbfworst);
    printf("    Here is the worst tet:\n");
    printtetvertssep(mesh, worstverts[0], worstverts[1], worstverts[2], worstverts[3]);
    printf("\n");
    printf("    Number of tets within %g degrees of worst: %d\n", degreesfromworst, numbadtets);
    printf("    Number of boundary vertices in these tets:\n");
    for (i=0; i<5; i++)
    {
        printf("        [%d]: %d\n", i, boundvertshist[i]);
    }
    printf("    Number of boundary edges in these tets:\n");
    for (i=0; i<7; i++)
    {
        printf("        [%d]: %d\n", i, boundedgeshist[i]);
    }
    printf("    Number of boundary faces in these tets:\n");
    for (i=0; i<5; i++)
    {
        printf("        [%d]: %d\n", i, boundfaceshist[i]);
    }
    printf("\n");
}

/* determine if there is threshold improvement in some mean */
bool localmeanimprove(starreal oldmeans[], starreal newmeans[], starreal threshold)
{
    int i;
    bool foundbetter = false;
    
    for (i=0; i<NUMMEANTHRESHOLDS; i++)
    {
        if (newmeans[i] > oldmeans[i])
        {
            /* see if it beats it by the required threshold */
            if (newmeans[i] - oldmeans[i] > threshold)
            {
                if (improvebehave.verbosity > 4)
                {
                    textcolor(BRIGHT, GREEN, BLACK);
                    printf("mean local improvement = %g, that's enough for success (needs %g)\n", newmeans[i] - oldmeans[i], threshold);
                    textcolor(RESET, WHITE, BLACK);
                }
                foundbetter = true;
            }
            else
            {
                if (improvebehave.verbosity > 4)
                {
                    printf("mean local improvement = %g, positive but not enough (needs %g)!\n", newmeans[i] - oldmeans[i], threshold);
                }
            }
        }
    }
    
    return foundbetter;
}










<|start_filename|>vtkVmtk/Segmentation/itkMedialCurveImageFilter.h<|end_filename|>
/*=========================================================================

Original Method Developed By:
  Module    : EvoLib
  File      : $RCSfile: itkMedialCurveImageFilter.h,v $
  Copyright : (C)opyright (University of Zaragoza) 2005++
              See COPYRIGHT statement in top level directory.
  Authors   : <NAME> && <NAME>
  Modified  : $Author: xmellado $
  Purpose   : Computation of the Medial curve of a tube like object.
  Date      : $Date: 2007/02/19 10:01:15 $
  Version   : $Revision: 1.2 $
  Changes   : $Locker:  $
              $Log: itkMedialCurveImageFilter.h,v $
              Revision 1.2  2007/02/19 10:01:15  xmellado
              Release v1.0

Modifications Made To Support Integration Into:
	The Vascular Modeling Toolkit (VMTK)
	www.vmtk.org

Modification Authors:
	<NAME>
		University at Buffalo
		Github: rlizzo
		Date: April 12, 2018
	<NAME>
		Orobix Srl.
		Github: lantiga
		Date: April 12, 2018

=========================================================================*/

#ifndef _itkMedialCurveImageFilter_h
#define _itkMedialCurveImageFilter_h

#include <time.h>

//STL
#include <functional>
#include <queue>

#include <itkImage.h>
#include <itkNeighborhoodIterator.h>
#include <itkImageRegionIterator.h>
#include <itkConstantBoundaryCondition.h>

#include <itkImageToImageFilter.h>

namespace itk
{

/// \brief Computation of the Medial curve of a tube like object.
///
/// The object is represented as a binary image. A topological prunning is performed guided
/// by the distance transform to the object. The prunning stops when all voxels that are end points
/// are not simple. The average outward flux imposes an extra criterion for deletion. This class implements the centerline extraction 
///	algorithm described in : "<NAME>, <NAME>, and <NAME>. Flux driven automatic centerline extraction. Technical Report
///	SOCS-04.2, School of Ccomputer Science, McGill University, 2004."

/// TODO:
/// 1. manual instantation
template< class TInputImage,
	  class TAverageOutwardFluxPixelType = float,
	  class TOutputPixelType = unsigned char>
class ITK_EXPORT MedialCurveImageFilter:
	public ImageToImageFilter<TInputImage, ::itk::Image<TOutputPixelType,TInputImage::ImageDimension> >
{
	public:

		//-----------------------------------------------------
		// Typedefs
		//-----------------------------------------------------

		typedef typename itk::Image< TAverageOutwardFluxPixelType, TInputImage::ImageDimension > TAverageOutwardFluxFImage;
		typedef typename itk::Image< TOutputPixelType, TInputImage::ImageDimension > TOutputImage;

		/** Standard class typedefs. */
		typedef MedialCurveImageFilter Self;
		typedef ImageToImageFilter<TInputImage,TOutputImage> Superclass;
		typedef SmartPointer<Self> Pointer;
		typedef SmartPointer<const Self> ConstPointer;

		/** Method for creation through the object factory */
		itkNewMacro(Self);

		/** Run-time type information (and related methods). */
		itkTypeMacro( MedialCurveImageFilter, ImageToImageFilter );

		typedef itk::ConstantBoundaryCondition< TOutputImage > OutputBCType;

		typedef typename TInputImage::ConstPointer InputConstPointerType;
		typedef typename TAverageOutwardFluxFImage::ConstPointer AOFConstPointerType;
		typedef typename TOutputImage::Pointer OutputPointerType;

		typedef typename TOutputImage::IndexType OutputIndexType;
		typedef typename TOutputImage::SizeType OutputSizeType;
		typedef typename TOutputImage::RegionType OutputRegionType;
		typedef typename TOutputImage::PixelType OutputPixelType;

		typedef typename TInputImage::IndexType InputIndexType;
		typedef typename TInputImage::PixelType InputPixelType;

		typedef itk::ImageRegionConstIterator< TInputImage > InputConstIteratorType;
		typedef itk::ImageRegionIterator< TOutputImage > OutputIteratorType;
		typedef itk::ConstNeighborhoodIterator< TInputImage > InputConstNeighborhoodIteratorType;
		typedef itk::ConstNeighborhoodIterator< TAverageOutwardFluxFImage > AOFConstNeighborhoodIteratorType;
		typedef itk::NeighborhoodIterator< TOutputImage > OutputNeighborhoodIteratorType;

		struct Pixel 
		{
			private:
				InputIndexType pixelIndex;
				InputPixelType pixelValue;

			public:
				InputPixelType GetPriority() const {return pixelValue;};
				void SetIndex(InputIndexType p) { pixelIndex=p;};
				void SetValue(InputPixelType v) {pixelValue=v;};
				InputIndexType GetIndex() {return pixelIndex;};
				InputPixelType GetValue() {return pixelValue;};
		};

		struct Greater:public std::binary_function<Pixel, Pixel, bool>
		{
			public:
				bool operator()(const Pixel &p1, const Pixel &p2)  const
				{
					return p1.GetPriority() > p2.GetPriority();
				}
		};

		typedef std::vector<Pixel> HeapContainer;
		typedef std::priority_queue<Pixel, HeapContainer, Greater > HeapType;

		/** The dimension of the input and output images. */
		itkStaticConstMacro(InputImageDimension, unsigned int,
			TInputImage::ImageDimension);
		itkStaticConstMacro(OutputImageDimension, unsigned int,
			TOutputImage::ImageDimension);


		//-----------------------------------------------------
		// Methods
		//-----------------------------------------------------

		virtual void SetAverageOutwardFluxImage(AOFConstPointerType aofImage)
		{
			this->ProcessObject::SetNthInput( 1, const_cast< TAverageOutwardFluxFImage * >(aofImage.GetPointer()) );
		}

		virtual AOFConstPointerType GetAverageOutwardFluxImage()
		{
			return ( static_cast< TAverageOutwardFluxFImage *>(this->ProcessObject::GetInput(1)) );
		}

		/** Set the AOF threshold. */
		itkSetMacro( Threshold, double );

		/** Get the AOF threshold . */
		itkGetConstReferenceMacro( Threshold, double );

#ifdef ITK_USE_CONCEPT_CHECKING
		/** Begin concept checking */
		itkConceptMacro(SameDimensionCheck,
			(Concept::SameDimension<InputImageDimension, OutputImageDimension>));
		itkConceptMacro(AOFIsFloatingPointCheck,
			(Concept::IsFloatingPoint<TAverageOutwardFluxPixelType>));
		/** End concept checking */
#endif

	protected:
		
		/// \brief Default Constructor
		MedialCurveImageFilter();

		/// \brief Destructor
		virtual ~MedialCurveImageFilter();

		///\brief Returns true if p belongs to the object and at least one of its 27 neighbors
		/// belong to the background.
		bool IsBoundary( OutputIndexType p );
    
		///\brief Returns true if its deletion from the object changes the local object topology
		/// in the 27 neighborhood.
		bool IsIntSimple( OutputIndexType p );

		///\brief Returns true if its deletion from the object changes the local background topology
		/// in the 18 neighborhood. 
		bool IsExtSimple( OutputIndexType p );

		///\brief Returns true if the point has less than two object neighbors.
		bool IsEnd( OutputIndexType p );

		///\brief Computes the binary object from its implicit representation.
		void DistanceToObject();

		/** Compute the medial curve. */
		void GenerateData() ITK_OVERRIDE;  

		void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE;


		//-----------------------------------------------------
		// Variables
		//-----------------------------------------------------
		
		InputConstPointerType distance; // Implicit representation of the object. Is at input 0.
		AOFConstPointerType aof;        // Average outward flux. Is at input 1.
		double m_Threshold;             // Threshold for the average outward flux.
		OutputPointerType queued;       // Image that stores queued labels in Update().
		OutputPointerType auxQueued;    // Image that stores queued labels in IsIntSimple() and IsExtSimple().
		OutputPointerType skeleton;     // Skeleton.
		OutputRegionType region;


	private:

		MedialCurveImageFilter( const MedialCurveImageFilter& );  //purposely not implemented
		void operator = ( const MedialCurveImageFilter& );  //purposely not implemented
};

#include "itkMedialCurveImageFilter.txx"

}//end itk namespace

#endif // _itkMedialCurveImageFilter_h



<|start_filename|>vtkVmtk/Segmentation/itkFastMarchingDirectionalFreezeImageFilter.h<|end_filename|>
/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: itkFastMarchingDirectionalFreezeImageFilter.h,v $
  Language:  C++
  Date:      $Date: 2006/09/01 21:33:26 $
  Version:   $Revision: 1.5 $

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#ifndef _itkFastMarchingDirectionalFreezeImageFilter_h
#define _itkFastMarchingDirectionalFreezeImageFilter_h

#include "itkFastMarchingUpwindGradientImageFilter.h"
#include "itkImage.h"

namespace itk
{
/** \class FastMarchingDirectionalFreezeImageFilter
 *
 * \brief Propagates a front freezing points based on the relative direction of 
 * the front and the gradient vector of the speed image.
 * 
 * 
 */
template <
  class TLevelSet, 
  class TSpeedImage = Image<float,TLevelSet::ImageDimension> >
class ITK_EXPORT FastMarchingDirectionalFreezeImageFilter :
    public FastMarchingUpwindGradientImageFilter<TLevelSet,TSpeedImage>
{

public:
  /** Standard class typdedefs. */
  typedef FastMarchingDirectionalFreezeImageFilter Self;
  typedef FastMarchingUpwindGradientImageFilter<TLevelSet,TSpeedImage> Superclass;
  typedef SmartPointer<Self> Pointer;
  typedef SmartPointer<const Self>  ConstPointer;

  /** Method for creation through the object factory. */
  itkNewMacro(Self);

  /** Run-time type information (and related methods). */
  itkTypeMacro(FastMarchingDirectionalFreezeImageFilter, FastMarchingUpwindGradientImageFilter);

  /** Inherited typedefs. */
  typedef typename Superclass::LevelSetType  LevelSetType;
  typedef typename Superclass::SpeedImageType SpeedImageType;
  typedef typename Superclass::LevelSetImageType  LevelSetImageType;
  typedef typename Superclass::LevelSetPointer  LevelSetPointer;
  typedef typename Superclass::SpeedImageConstPointer  SpeedImageConstPointer;
  typedef typename Superclass::LabelImageType  LabelImageType;
  typedef typename Superclass::PixelType  PixelType;
  typedef typename Superclass::AxisNodeType  AxisNodeType;
  typedef typename Superclass::NodeType  NodeType;
  typedef typename Superclass::NodeContainer  NodeContainer;
  typedef typename Superclass::NodeContainerPointer  NodeContainerPointer;
  typedef typename Superclass::IndexType  IndexType;
  typedef typename Superclass::OutputSpacingType  OutputSpacingType;
  typedef typename Superclass::LevelSetIndexType  LevelSetIndexType;
  typedef typename Superclass::GradientImageType  GradientImageType;
  typedef typename Superclass::GradientImagePointer  GradientImagePointer;
  typedef typename Superclass::GradientPixelType  GradientPixelType;

  typedef typename SpeedImageType::PixelType SpeedPixelType;

  /** The dimension of the level set. */
  itkStaticConstMacro(SetDimension, unsigned int,Superclass::SetDimension); 

#ifdef ITK_USE_CONCEPT_CHECKING
  /** Begin concept checking */
  /** End concept checking */
#endif

  /** SpeedGradientPixel typedef support. */
  typedef CovariantVector<SpeedPixelType,
          itkGetStaticConstMacro(SetDimension)> SpeedGradientPixelType;

  /** SpeedGradientImage typedef support. */
  typedef Image<SpeedGradientPixelType,
          itkGetStaticConstMacro(SetDimension)> SpeedGradientImageType;

  /** SpeedGradientImagePointer typedef support. */
  typedef typename SpeedGradientImageType::Pointer SpeedGradientImagePointer;

  /** Get the speed gradient image. */
  SpeedGradientImagePointer GetSpeedGradientImage() const
  { return m_SpeedGradientImage; };

  //TODO: Set the speed gradient image from outside 

protected:
  FastMarchingDirectionalFreezeImageFilter();
  ~FastMarchingDirectionalFreezeImageFilter(){};
  void PrintSelf( std::ostream& os, Indent indent ) const ITK_OVERRIDE;

  void GenerateData() ITK_OVERRIDE;

  void AllocateSpeedGradientImage();
  void ComputeSpeedGradientImage();

  GradientPixelType ComputeGradientValue( const IndexType& index ,
                                const LevelSetImageType * output);

  virtual void UpdateNeighbors( const IndexType& index,
                                const SpeedImageType *, LevelSetImageType * ) ITK_OVERRIDE;

private:
  FastMarchingDirectionalFreezeImageFilter(const Self&); //purposely not implemented
  void operator=(const Self&); //purposely not implemented
 
  SpeedGradientImagePointer m_SpeedGradientImage; 
};

} // namespace itk


#ifndef ITK_MANUAL_INSTANTIATION
#include "itkFastMarchingDirectionalFreezeImageFilter.txx"
#endif

#endif


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkUnstructuredGridCenterlineGroupsClipper.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkUnstructuredGridCenterlineGroupsClipper.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:46:43 $
Version:   $Revision: 1.9 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkUnstructuredGridCenterlineGroupsClipper.h"
#include "vtkExecutive.h"
#include "vtkPointData.h"
#include "vtkCellData.h"
#include "vtkIntArray.h"
#include "vtkDoubleArray.h"
#include "vtkClipDataSet.h"
#include "vtkvmtkAppendFilter.h"
#include "vtkvmtkPolyBallLine.h"
#include "vtkMath.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkVersion.h"

#include "vtkvmtkConstants.h"


vtkStandardNewMacro(vtkvmtkUnstructuredGridCenterlineGroupsClipper);

vtkvmtkUnstructuredGridCenterlineGroupsClipper::vtkvmtkUnstructuredGridCenterlineGroupsClipper()
{
  this->Centerlines = NULL;
  this->CenterlineGroupIdsArrayName = NULL;
  this->CenterlineRadiusArrayName = NULL;
  this->GroupIdsArrayName = NULL;
  this->BlankingArrayName = NULL;
  this->CenterlineGroupIds = NULL;
  this->ClipAllCenterlineGroupIds = 0;
  this->CutoffRadiusFactor = VTK_VMTK_LARGE_DOUBLE;
  this->ClipValue = 0.0; 
  this->UseRadiusInformation = 1; 
 
  this->SetNumberOfOutputPorts(2);
  this->GenerateClippedOutput = 0;
  vtkUnstructuredGrid *output2 = vtkUnstructuredGrid::New();
  this->GetExecutive()->SetOutputData(1, output2);
  output2->Delete();
}

vtkvmtkUnstructuredGridCenterlineGroupsClipper::~vtkvmtkUnstructuredGridCenterlineGroupsClipper()
{
  if (this->Centerlines)
    {
    this->Centerlines->Delete();
    this->Centerlines = NULL;
    }

  if (this->CenterlineGroupIds)
    {
    this->CenterlineGroupIds->Delete();
    this->CenterlineGroupIds = NULL;
    }

  if (this->CenterlineGroupIdsArrayName)
    {
    delete[] this->CenterlineGroupIdsArrayName;
    this->CenterlineGroupIdsArrayName = NULL;
    }

  if (this->CenterlineRadiusArrayName)
    {
    delete[] this->CenterlineRadiusArrayName;
    this->CenterlineRadiusArrayName = NULL;
    }

  if (this->GroupIdsArrayName)
    {
    delete[] this->GroupIdsArrayName;
    this->GroupIdsArrayName = NULL;
    }

  if (this->BlankingArrayName)
    {
    delete[] this->BlankingArrayName;
    this->BlankingArrayName = NULL;
    }
}

vtkUnstructuredGrid *vtkvmtkUnstructuredGridCenterlineGroupsClipper::GetClippedOutput()
{
  if (this->GetNumberOfOutputPorts() < 2)
    {
    return NULL;
    }

  return vtkUnstructuredGrid::SafeDownCast(this->GetExecutive()->GetOutputData(1));
}

int vtkvmtkUnstructuredGridCenterlineGroupsClipper::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkUnstructuredGrid *input = vtkUnstructuredGrid::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkDataArray* centerlineGroupIdsArray;
  vtkIntArray* blankingArray;
  vtkIntArray* groupIdsArray;

  if (!this->Centerlines)
    {
    vtkErrorMacro(<< "Centerlines not set.");
    return 1;
    }

  if (!this->ClipAllCenterlineGroupIds && !this->CenterlineGroupIds)
    {
    vtkErrorMacro(<< "CenterlineGroupIds not set.");
    return 1;
    }

  if (!this->CenterlineGroupIdsArrayName)
    {
    vtkErrorMacro(<< "CenterlineGroupIdsArrayName not set.");
    return 1;
    }

  if (!this->GroupIdsArrayName)
    {
    vtkErrorMacro(<< "GroupIdsArrayName not set.");
    return 1;
    }

  centerlineGroupIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineGroupIdsArrayName);

  if (!centerlineGroupIdsArray)
    {
    vtkErrorMacro(<< "CenterlineGroupIdsArray with name specified does not exist");
    return 1;
    }

  if (!this->BlankingArrayName)
    {
    vtkErrorMacro(<< "BlankingArrayName not set.");
    return 1;
    }

  blankingArray = vtkIntArray::SafeDownCast(this->Centerlines->GetCellData()->GetArray(this->BlankingArrayName));

  if (!blankingArray)
    {
    vtkErrorMacro(<< "BlankingArrayName with name specified does not exist");
    return 1;
    }

  if (!this->CenterlineRadiusArrayName)
    {
    vtkErrorMacro(<< "CenterlineRadiusArrayName not set.");
    return 1;
    }

  if (!this->Centerlines->GetPointData()->GetArray(this->CenterlineRadiusArrayName))
    {
    vtkErrorMacro(<< "CenterlineRadiusArray with name specified does not exist");
    return 1;
    }

  if (this->Centerlines->GetNumberOfCells() == 1)
    {
    output->DeepCopy(input);
    groupIdsArray = vtkIntArray::New();
    groupIdsArray->SetName(this->GroupIdsArrayName);
    groupIdsArray->SetNumberOfTuples(output->GetNumberOfPoints());
    groupIdsArray->FillComponent(0,centerlineGroupIdsArray->GetComponent(0,0));
    output->GetPointData()->AddArray(groupIdsArray);
    groupIdsArray->Delete();
    return 1;
    }
  
  vtkvmtkAppendFilter* appendBranches = vtkvmtkAppendFilter::New();
  appendBranches->MergeDuplicatePointsOff();
  vtkvmtkAppendFilter* appendClippedOutput = NULL;
  if (this->GenerateClippedOutput)
    {
    appendClippedOutput = vtkvmtkAppendFilter::New();
    appendClippedOutput->MergeDuplicatePointsOff();
    }

  // for each group, compute the clipping array, clip, add group ids array and append.

  vtkvmtkPolyBallLine* groupTubes = vtkvmtkPolyBallLine::New();
  groupTubes->SetInput(this->Centerlines);
  groupTubes->SetPolyBallRadiusArrayName(this->CenterlineRadiusArrayName);
  groupTubes->SetUseRadiusInformation(this->UseRadiusInformation);

  vtkvmtkPolyBallLine* nonGroupTubes = vtkvmtkPolyBallLine::New();
  nonGroupTubes->SetInput(this->Centerlines);
  nonGroupTubes->SetPolyBallRadiusArrayName(this->CenterlineRadiusArrayName);
  nonGroupTubes->SetUseRadiusInformation(this->UseRadiusInformation);

  int numberOfPoints = input->GetNumberOfPoints();

  const char clippingArrayName[] = "ClippingArray";

  vtkDoubleArray* clippingArray = vtkDoubleArray::New();
  clippingArray->SetNumberOfComponents(1);
  clippingArray->SetNumberOfTuples(numberOfPoints);
  clippingArray->FillComponent(0,0.0);
  clippingArray->SetName(clippingArrayName);

  vtkUnstructuredGrid* clippingInput = vtkUnstructuredGrid::New();
  clippingInput->DeepCopy(input);
  clippingInput->GetPointData()->AddArray(clippingArray);
  clippingInput->GetPointData()->SetActiveScalars(clippingArrayName);

  vtkIdList* groupTubesGroupIds = vtkIdList::New();
  vtkIdList* nonGroupTubesGroupIds = vtkIdList::New();

  double point[3];
  double groupTubeValue, nonGroupTubeValue, tubeDifferenceValue;

  vtkIdType groupId;

  vtkIdList* centerlineGroupIds = vtkIdList::New();
 
  int i;
  if (this->ClipAllCenterlineGroupIds)
    {
    for (i=0; i<centerlineGroupIdsArray->GetNumberOfTuples(); i++)
      {
      if (blankingArray->GetValue(i) == 1)
        {
        continue;
        }
      centerlineGroupIds->InsertUniqueId(static_cast<vtkIdType>(vtkMath::Round(centerlineGroupIdsArray->GetComponent(i,0))));
      }
    }
  else
    {
    centerlineGroupIds->DeepCopy(this->CenterlineGroupIds);
    }

  for (i=0; i<centerlineGroupIds->GetNumberOfIds(); i++)
    {
    groupId = centerlineGroupIds->GetId(i);

    groupTubesGroupIds->Initialize();
    nonGroupTubesGroupIds->Initialize();

    for (int j=0; j<this->Centerlines->GetNumberOfCells(); j++)
      {
      if (blankingArray->GetValue(j) == 1)
        {
        continue;
        }
      if (static_cast<vtkIdType>(vtkMath::Round(centerlineGroupIdsArray->GetComponent(j,0))) == groupId)
        {
        groupTubesGroupIds->InsertNextId(j);
        }
      else
        {
        nonGroupTubesGroupIds->InsertNextId(j);
        }
      }

    if ((groupTubesGroupIds->GetNumberOfIds() == 0) || (nonGroupTubesGroupIds->GetNumberOfIds() == 0))
      {
      continue;
      }

    groupTubes->SetInputCellIds(groupTubesGroupIds);
    nonGroupTubes->SetInputCellIds(nonGroupTubesGroupIds);

    for (int k=0; k<numberOfPoints; k++)
      {
      input->GetPoint(k,point);
      groupTubeValue = groupTubes->EvaluateFunction(point);
      if (groupTubeValue > this->CutoffRadiusFactor * this->CutoffRadiusFactor - 1)
        {
        groupTubeValue = VTK_VMTK_LARGE_DOUBLE;
        }
      nonGroupTubeValue = nonGroupTubes->EvaluateFunction(point);
      tubeDifferenceValue = nonGroupTubeValue - groupTubeValue;
      clippingArray->SetValue(k,tubeDifferenceValue);
      }

    vtkClipDataSet* clipper = vtkClipDataSet::New();
#if (VTK_MAJOR_VERSION <= 5)
    clipper->SetInput(clippingInput);
#else
    clipper->SetInputData(clippingInput);
#endif
    clipper->SetValue(this->ClipValue);
    clipper->GenerateClipScalarsOff();
    clipper->SetGenerateClippedOutput(this->GenerateClippedOutput);
    clipper->Update();

    if (clipper->GetOutput()->GetNumberOfPoints()==0)
      {
      clipper->Delete();
      continue;
      }

    vtkUnstructuredGrid* clippedBranch = vtkUnstructuredGrid::New();
    clippedBranch->DeepCopy(clipper->GetOutput());

    if (this->GenerateClippedOutput)
      {
      vtkUnstructuredGrid* clippedOutputBranch = vtkUnstructuredGrid::New();
      clippedOutputBranch->DeepCopy(clipper->GetClippedOutput());
#if (VTK_MAJOR_VERSION <= 5)
      appendClippedOutput->AddInput(clippedOutputBranch);
#else
      appendClippedOutput->AddInputData(clippedOutputBranch);
#endif
      clippedOutputBranch->Delete();
      }
    
    groupIdsArray = vtkIntArray::New();
    groupIdsArray->SetName(this->GroupIdsArrayName);
    groupIdsArray->SetNumberOfTuples(clippedBranch->GetNumberOfPoints());
    groupIdsArray->FillComponent(0,groupId);

    clippedBranch->GetPointData()->AddArray(groupIdsArray);
#if (VTK_MAJOR_VERSION <= 5)
    appendBranches->AddInput(clippedBranch);
#else
    appendBranches->AddInputData(clippedBranch);
#endif
    groupIdsArray->Delete();
    clippedBranch->Delete();
    clipper->Delete();
    }

  appendBranches->Update();

  output->DeepCopy(appendBranches->GetOutput());

  if (this->GenerateClippedOutput)
    {
    appendClippedOutput->Update();
    this->GetClippedOutput()->DeepCopy(appendClippedOutput->GetOutput());
    appendClippedOutput->Delete();
    }

  clippingArray->Delete();
  clippingInput->Delete();
  appendBranches->Delete();
  groupTubes->Delete();
  nonGroupTubes->Delete();
  groupTubesGroupIds->Delete();
  nonGroupTubesGroupIds->Delete();
  centerlineGroupIds->Delete();

  return 1;
}

void vtkvmtkUnstructuredGridCenterlineGroupsClipper::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkSparseMatrixRow.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkSparseMatrixRow.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:44 $
  Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkSparseMatrixRow - Class to handle operating on rows of a sparse matrix. 
// .SECTION Description
// ..

#ifndef __vtkvmtkSparseMatrixRow_h
#define __vtkvmtkSparseMatrixRow_h

#include "vtkObject.h"
#include "vtkvmtkStencil.h"
#include "vtkvmtkNeighborhood.h"
#include "vtkvmtkConstants.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkSparseMatrixRow : public vtkObject 
{
public:

  static vtkvmtkSparseMatrixRow *New();
  vtkTypeMacro(vtkvmtkSparseMatrixRow,vtkObject);

  vtkIdType GetElementId(vtkIdType i) { return this->ElementIds[i]; }
  void SetElementId(vtkIdType i, vtkIdType id) { this->ElementIds[i] = id; }

  double GetElement(vtkIdType i) { return this->Elements[i]; }
  void SetElement(vtkIdType i, double element) { this->Elements[i] = element; }

  vtkIdType GetElementIndex(vtkIdType id);

  vtkIdType GetNumberOfElements() { return this->NElements; }
  void SetNumberOfElements(vtkIdType numberOfElements);

  vtkSetMacro(DiagonalElement,double);
  vtkGetMacro(DiagonalElement,double);

  void Initialize();

  void CopyStencil(vtkvmtkStencil* stencil);
  void CopyNeighborhood(vtkvmtkNeighborhood* neighborhood);

  // Description:
  // Standard DeepCopy method.  Since this object contains no reference
  // to other objects, there is no ShallowCopy.
  void DeepCopy(vtkvmtkSparseMatrixRow *src);

protected:
  vtkvmtkSparseMatrixRow();
  ~vtkvmtkSparseMatrixRow();

  vtkIdType* ElementIds;
  double* Elements;
  double DiagonalElement;
  vtkIdType NElements;

private:
  vtkvmtkSparseMatrixRow(const vtkvmtkSparseMatrixRow&);  // Not implemented.
  void operator=(const vtkvmtkSparseMatrixRow&);  // Not implemented.
};

#endif



<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineUtilities.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkCenterlineUtilities.cxx,v $
Language:  C++
Date:      $Date: 2006/10/17 15:16:16 $
Version:   $Revision: 1.5 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkCenterlineUtilities.h"
#include "vtkPolyData.h"
#include "vtkPointData.h"
#include "vtkCellData.h"
#include "vtkIdList.h"
#include "vtkPolyLine.h"
#include "vtkMath.h"
#include "vtkvmtkConstants.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkCenterlineUtilities);

vtkIdType vtkvmtkCenterlineUtilities::GetMaxGroupId(vtkPolyData* centerlines, const char* groupIdsArrayName)
{
  vtkDataArray* groupIdsArray = centerlines->GetCellData()->GetArray(groupIdsArrayName);

  int numberOfCells = centerlines->GetNumberOfCells();
  vtkIdType maxGroupId = -1;

  int i;
  for (i=0; i<numberOfCells; i++)
    {
    vtkIdType groupId = static_cast<int>(groupIdsArray->GetComponent(i,0));
    if (groupId > maxGroupId)
      {
      maxGroupId = groupId;
      }
    }

  return maxGroupId;
}

void vtkvmtkCenterlineUtilities::GetGroupsIdList(vtkPolyData* centerlines, const char* groupIdsArrayName, const char* blankingArrayName, int blanked, vtkIdList* groupIds)
{
  vtkDataArray* groupIdsArray = centerlines->GetCellData()->GetArray(groupIdsArrayName);

  vtkDataArray* blankingArray = NULL;
  
  if (blankingArrayName)
  {          
    blankingArray = centerlines->GetCellData()->GetArray(blankingArrayName);
  }
  
  int numberOfCells = centerlines->GetNumberOfCells();

  groupIds->Initialize();

  int i;
  for (i=0; i<numberOfCells; i++)
    {
    vtkIdType groupId = static_cast<int>(groupIdsArray->GetComponent(i,0));

    if (blankingArray)
    {
      vtkIdType current_blanked = static_cast<int>(blankingArray->GetComponent(i,0));
      if (blanked != current_blanked)
      {
        continue;
      }
    }
    groupIds->InsertUniqueId(groupId);
    }
}
 
void vtkvmtkCenterlineUtilities::GetGroupsIdList(vtkPolyData* centerlines, const char* groupIdsArrayName, vtkIdList* groupIds)
{
  vtkvmtkCenterlineUtilities::GetGroupsIdList(centerlines,groupIdsArrayName,NULL,0,groupIds);
}

void vtkvmtkCenterlineUtilities::GetNonBlankedGroupsIdList(vtkPolyData* centerlines, const char* groupIdsArrayName, const char* blankingArrayName, vtkIdList* groupIds)
{
  vtkvmtkCenterlineUtilities::GetGroupsIdList(centerlines,groupIdsArrayName,blankingArrayName,0,groupIds);
}
  
void vtkvmtkCenterlineUtilities::GetBlankedGroupsIdList(vtkPolyData* centerlines, const char* groupIdsArrayName, const char* blankingArrayName, vtkIdList* groupIds)
{
  vtkvmtkCenterlineUtilities::GetGroupsIdList(centerlines,groupIdsArrayName,blankingArrayName,1,groupIds);
}

void vtkvmtkCenterlineUtilities::GetGroupCellIds(vtkPolyData* centerlines, const char* groupIdsArrayName, vtkIdType groupId, vtkIdList* groupCellIds)
{
  vtkDataArray* groupIdsArray = centerlines->GetCellData()->GetArray(groupIdsArrayName);
  int numberOfCells = centerlines->GetNumberOfCells();

  groupCellIds->Initialize();
  
  int i;
  for (i=0; i<numberOfCells; i++)
  {
    vtkIdType current_groupId = static_cast<int>(groupIdsArray->GetComponent(i,0));
    if (current_groupId != groupId)
    {
      continue;
    }
    groupCellIds->InsertNextId(i);
  }
}

void vtkvmtkCenterlineUtilities::GetGroupUniqueCellIds(vtkPolyData* centerlines, const char* groupIdsArrayName, vtkIdType groupId, vtkIdList* groupCellIds)
{
  vtkDataArray* groupIdsArray = centerlines->GetCellData()->GetArray(groupIdsArrayName);
  int numberOfCells = centerlines->GetNumberOfCells();

  groupCellIds->Initialize();

  int i;
  for (i=0; i<numberOfCells; i++)
    {
    vtkIdType current_groupId = static_cast<int>(groupIdsArray->GetComponent(i,0));
    if (current_groupId != groupId)
      {
      continue;
      }
    int currentNumberOfGroupCellIds = groupCellIds->GetNumberOfIds();
    bool duplicate = false;
    int j;
    for (j=0; j<currentNumberOfGroupCellIds; j++)
      {
      double currentCellFirstPoint[3], currentCellLastPoint[3];
      double cellFirstPoint[3], cellLastPoint[3];
      vtkCell* cell = centerlines->GetCell(groupCellIds->GetId(j));
      cell->GetPoints()->GetPoint(0,currentCellFirstPoint);
      cell->GetPoints()->GetPoint(cell->GetNumberOfPoints()-1,currentCellLastPoint);
      cell = centerlines->GetCell(i);
      cell->GetPoints()->GetPoint(0,cellFirstPoint);
      cell->GetPoints()->GetPoint(cell->GetNumberOfPoints()-1,cellLastPoint);
      if ((vtkMath::Distance2BetweenPoints(currentCellFirstPoint,cellFirstPoint) < VTK_VMTK_DOUBLE_TOL) &&
          (vtkMath::Distance2BetweenPoints(currentCellLastPoint,cellLastPoint) < VTK_VMTK_DOUBLE_TOL))
        {
        duplicate = true;
        break;
        }
      }
    if (duplicate)
      {
      continue;
      }
    groupCellIds->InsertNextId(i);
    }
}

void vtkvmtkCenterlineUtilities::GetCenterlineCellIds(vtkPolyData* centerlines, const char* centerlineIdsArrayName, vtkIdType centerlineId, vtkIdList* centerlineCellIds)
{
  vtkDataArray* centerlineIdsArray = centerlines->GetCellData()->GetArray(centerlineIdsArrayName);
  int numberOfCells = centerlines->GetNumberOfCells();

  centerlineCellIds->Initialize();
  
  int i;
  for (i=0; i<numberOfCells; i++)
  {
    vtkIdType currentCenterlineId = static_cast<int>(centerlineIdsArray->GetComponent(i,0));
    if (currentCenterlineId != centerlineId)
    {
      continue;
    }
    centerlineCellIds->InsertNextId(i);
  }
}

void vtkvmtkCenterlineUtilities::GetCenterlineCellIds(vtkPolyData* centerlines, const char* centerlineIdsArrayName, const char* tractIdsArrayName, vtkIdType centerlineId, vtkIdList* centerlineCellIds)
{
  vtkDataArray* centerlineIdsArray = centerlines->GetCellData()->GetArray(centerlineIdsArrayName);
  vtkDataArray* tractIdsArray = centerlines->GetCellData()->GetArray(tractIdsArrayName);
  int numberOfCells = centerlines->GetNumberOfCells();

  centerlineCellIds->Initialize();
  vtkIdList* centerlineTractIds = vtkIdList::New();
  
  int i;
  for (i=0; i<numberOfCells; i++)
  {
    vtkIdType currentCenterlineId = static_cast<int>(centerlineIdsArray->GetComponent(i,0));
    if (currentCenterlineId != centerlineId)
    {
      continue;
    }
    centerlineCellIds->InsertNextId(i);
    vtkIdType currectTractId = static_cast<int>(tractIdsArray->GetComponent(i,0));
    centerlineTractIds->InsertNextId(currectTractId);
  }

  int numberOfCenterlineCellIds = centerlineCellIds->GetNumberOfIds();
  
  bool done = false;
  while (!done)
    {
    done = true;
    for (i=0; i<numberOfCenterlineCellIds-1; i++)
      {
      if (centerlineTractIds->GetId(i) > centerlineTractIds->GetId(i+1))
        {
        vtkIdType tmp = centerlineTractIds->GetId(i+1);
        centerlineTractIds->SetId(i+1,centerlineTractIds->GetId(i));
        centerlineTractIds->SetId(i,tmp);
        tmp = centerlineCellIds->GetId(i+1);
        centerlineCellIds->SetId(i+1,centerlineCellIds->GetId(i));
        centerlineCellIds->SetId(i,tmp);
        done = false;
        }
      }
    }
  
  centerlineTractIds->Delete();
}

int vtkvmtkCenterlineUtilities::IsGroupBlanked(vtkPolyData* centerlines, const char* groupIdsArrayName, const char* blankingArrayName, vtkIdType groupId)
{
  vtkDataArray* groupIdsArray = centerlines->GetCellData()->GetArray(groupIdsArrayName);
  int numberOfCells = centerlines->GetNumberOfCells();

  vtkIdType cellId = -1;
  int i;
  for (i=0; i<numberOfCells; i++)
  {
    vtkIdType current_groupId = static_cast<int>(groupIdsArray->GetComponent(i,0));
    if (current_groupId != groupId)
    {
      continue;
    }
    cellId = i;
    break;
  }

  if (cellId == -1)
  {
    return -1;
  }
  
  return vtkvmtkCenterlineUtilities::IsCellBlanked(centerlines,blankingArrayName,cellId);
}
  
int vtkvmtkCenterlineUtilities::IsCellBlanked(vtkPolyData* centerlines, const char* blankingArrayName, vtkIdType cellId)
{
  vtkDataArray* blankingArray = centerlines->GetCellData()->GetArray(blankingArrayName);
  int blanking = static_cast<int>(blankingArray->GetComponent(cellId,0));
  int isBlanked = blanking == 1 ? 1 : 0;
  return isBlanked;
}
  
void vtkvmtkCenterlineUtilities::FindAdjacentCenterlineGroupIds(vtkPolyData* centerlines, const char* groupIdsArrayName, const char* centerlineIdsArrayName, const char* tractIdsArrayName, vtkIdType groupId, vtkIdList* upStreamGroupIds, vtkIdList* downStreamGroupIds)
{
  upStreamGroupIds->Initialize();
  downStreamGroupIds->Initialize();

  vtkDataArray* centerlineGroupIdsArray = centerlines->GetCellData()->GetArray(groupIdsArrayName);
  vtkDataArray* centerlineIdsArray = centerlines->GetCellData()->GetArray(centerlineIdsArrayName);
  vtkDataArray* centerlineTractIdsArray = centerlines->GetCellData()->GetArray(tractIdsArrayName);

  int numberOfCenterlineCells = centerlines->GetNumberOfCells();

  int i;
  for (i=0; i<numberOfCenterlineCells; i++)
    {
    vtkIdType branchGroupId = static_cast<int>(centerlineGroupIdsArray->GetComponent(i,0));

    if (branchGroupId != groupId)
      {
      continue;
      }

    vtkCell* centerlineBranch = centerlines->GetCell(i);
    if (centerlineBranch->GetCellType() != VTK_LINE && centerlineBranch->GetCellType() != VTK_POLY_LINE)
      {
      continue;
      }

    vtkIdType branchCenterlineId = static_cast<int>(centerlineIdsArray->GetComponent(i,0));
    vtkIdType branchCenterlineTractId = static_cast<int>(centerlineTractIdsArray->GetComponent(i,0));

    int j;
    for (j=0; j<numberOfCenterlineCells; j++)
      {
      vtkIdType currentBranchCenterlineGroupId = static_cast<int>(centerlineGroupIdsArray->GetComponent(j,0));
      vtkIdType currentBranchCenterlineId = static_cast<int>(centerlineIdsArray->GetComponent(j,0));
      vtkIdType currentBranchCenterlineTractId = static_cast<int>(centerlineTractIdsArray->GetComponent(j,0));

      if (currentBranchCenterlineGroupId == branchGroupId)
        {
        continue;
        }

      if (currentBranchCenterlineId != branchCenterlineId)
        {
        continue;
        }

      //WARNING: this assumes that tract ids are adjacent
      if (currentBranchCenterlineTractId == branchCenterlineTractId - 1)
        {
        upStreamGroupIds->InsertUniqueId(currentBranchCenterlineGroupId);
        }

      if (currentBranchCenterlineTractId == branchCenterlineTractId + 1)
        {
        downStreamGroupIds->InsertUniqueId(currentBranchCenterlineGroupId);
        }
      }
    }
}

void vtkvmtkCenterlineUtilities::InterpolatePoint(vtkPolyData* centerlines, int cellId, int subId, double pcoord, double interpolatedPoint[3])
{
  double point0[3], point1[3];
  vtkPoints* centerlineCellPoints = centerlines->GetCell(cellId)->GetPoints();
  centerlineCellPoints->GetPoint(subId,point0);
  centerlineCellPoints->GetPoint(subId+1,point1);
      
  interpolatedPoint[0] = (1.0 - pcoord) * point0[0] + pcoord * point1[0];
  interpolatedPoint[1] = (1.0 - pcoord) * point0[1] + pcoord * point1[1];
  interpolatedPoint[2] = (1.0 - pcoord) * point0[2] + pcoord * point1[2];
}

void vtkvmtkCenterlineUtilities::InterpolateTuple(vtkPolyData* centerlines, const char* arrayName, int cellId, int subId, double pcoord, double* interpolatedTuple)
{
  vtkDataArray* array = centerlines->GetPointData()->GetArray(arrayName);
  int numberOfComponents = array->GetNumberOfComponents();
  vtkIdType pointId0 = centerlines->GetCell(cellId)->GetPointId(subId);
  vtkIdType pointId1 = centerlines->GetCell(cellId)->GetPointId(subId+1);
  double* tuple0 = array->GetTuple(pointId0);
  double* tuple1 = array->GetTuple(pointId1);

  int i;
  for (i=0; i<numberOfComponents; i++)
  {
    interpolatedTuple[i] = (1.0 - pcoord) * tuple0[i] + pcoord * tuple1[i];
  }
}

void vtkvmtkCenterlineUtilities::FindMergingPoints(vtkPolyData* centerlines, vtkPoints* mergingPoints, double tolerance=1E-8)
{
  mergingPoints->Initialize();
  int numberOfCells = centerlines->GetNumberOfCells();
  int i, j, k;
  for (i=0; i<numberOfCells; i++)
    {
    vtkCell* centerline = centerlines->GetCell(i);
    int numberOfCenterlinePoints = centerline->GetNumberOfPoints();
    int previousMergeStatus = -1;
    int mergeStatus = -1;
    for (j=0; j<numberOfCenterlinePoints; j++)
      {
      double point[3];
      centerline->GetPoints()->GetPoint(j,point);
      for (k=i+1; k<numberOfCells; k++)
        {
        vtkCell* currentCenterline = centerlines->GetCell(k);
        int numberOfCurrentCenterlinePoints = currentCenterline->GetNumberOfPoints();
        double closestPoint[3];
        int subId;
        double pcoords[3];
        double dist2;
        double* weights = new double[numberOfCurrentCenterlinePoints];
        currentCenterline->EvaluatePosition(point,closestPoint,subId,pcoords,dist2,weights);
        if (dist2 < tolerance*tolerance)
          {
          mergeStatus = 1;
          }
        else
          {
          mergeStatus = 0;
          }
        if (j>0 && mergeStatus != previousMergeStatus)
          {
          mergingPoints->InsertNextPoint(point);
          previousMergeStatus = mergeStatus;
          }
        delete[] weights;
        }
      } 
    }
}



<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/main.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*  main()                                                                   */
/*                                                                           */
/*  This is basically a harness function to use Star to read in an existing  */
/*  tetrahedral mesh, perform the improvement, and then output the improved  */
/*  mesh. It will undoubtedly need to be updated and generalized as Star's   */
/*  mesh generation capabilities mature (e.g., the ability to read in        */
/*  constraining facets or tetrahedralize arbitrary inputs).                 */
/*                                                                           */
/*****************************************************************************/

int main(int argc,
         char **argv)
{
  struct behavior behave;
  struct inputs in;
  struct outputs out;
  struct proxipool vertexpool;
  struct tetcomplex mesh;
  FILE *polyfile;

  primitivesinit();
  
  /* tack on -rNE every time, to enforce standard Star behavior */
  argv[argc] = "-rNE";
  argc += 1;
  
  /* call Star's command line parsing */
  parsecommandline(argc, argv, &behave);
  polyfile = inputverticesreadsortstore(&behave, &in, &vertexpool);

  /* parse improvement options */
  parseimprovecommandline(argc, argv, &improvebehave);

  /* Compute an array mapping vertex numbers to their tags. */
  inputmaketagmap(&vertexpool, in.firstnumber, in.vertextags);
  /* Read and reconstruct a mesh. */
  inputtetrahedra(&behave, &in, &vertexpool, &out, &mesh);

  /*********************************************************/
  /* IMPROVEMENT HAPPENS HERE                              */
  /*********************************************************/
  staticimprove(&behave, &in, &vertexpool, &mesh, argc, argv);

  /* Free the array of vertex tags allocated by inputall(). */
  if (in.vertextags != (tag *) NULL) {
    starfree(in.vertextags);
    in.vertextags = (tag *) NULL;
  }
  /* Free the pool of vertices initialized by inputall(). */
  proxipooldeinit(&vertexpool);

  return 0;
}


<|start_filename|>vtkVmtk/Segmentation/vtkvmtkAnisotropicDiffusionImageFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkAnisotropicDiffusionImageFilter.h,v $
Language:  C++
Date:      $Date: 2018/03/05 16:48:25 $
Version:   $Revision: 1.4 $

  Copyright (c) <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.
  Note: this class was contributed by 
      <NAME>
      https://github.com/kayarre

=========================================================================*/
// .NAME vtkvmtkAnisotropicDiffusionImageFilter - Wrapper class around itk::GradientAnisotropicDiffusionImageFilter
// .SECTION Description
// vtkvmtkAnisotropicDiffusionImageFilter


#ifndef __vtkvmtkAnisotropicDiffusionImageFilter_h
#define __vtkvmtkAnisotropicDiffusionImageFilter_h

#include "vtkSimpleImageToImageFilter.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkAnisotropicDiffusionImageFilter : public vtkSimpleImageToImageFilter
{
 public:
  static vtkvmtkAnisotropicDiffusionImageFilter *New();
  vtkTypeMacro(vtkvmtkAnisotropicDiffusionImageFilter, vtkSimpleImageToImageFilter);

  vtkGetMacro(NumberOfIterations,int);
  vtkSetMacro(NumberOfIterations,int);

  vtkGetMacro(TimeStep,double);
  vtkSetMacro(TimeStep,double);

  vtkGetMacro(Conductance,double);
  vtkSetMacro(Conductance,double);


protected:

  vtkvmtkAnisotropicDiffusionImageFilter();
  ~vtkvmtkAnisotropicDiffusionImageFilter() {};

  virtual void SimpleExecute(vtkImageData* input, vtkImageData* output) VTK_OVERRIDE;

private:
  template< class TImage >
  int FilterImage( vtkImageData*, vtkImageData*, typename TImage::Pointer );
  
  template< int VDimension >
  int FilterScalarImage( vtkImageData* , vtkImageData* , int );
  
  vtkvmtkAnisotropicDiffusionImageFilter(const vtkvmtkAnisotropicDiffusionImageFilter&);  // Not implemented.
  void operator=(const vtkvmtkAnisotropicDiffusionImageFilter&);  // Not implemented.

  int NumberOfIterations;
  double TimeStep;
  double Conductance;
  
};

#endif



<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/vector.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*  Simple vector math convenience functions                                 */
/*                                                                           */
/*****************************************************************************/

/* compute the dot product of two vectors u and v */
starreal dot(starreal u[3],
           starreal v[3])
{
    return u[0]*v[0] + u[1]*v[1] + u[2]*v[2];
}

/* compute the cross product of two vectors u and v */
void cross(starreal u[3],
           starreal v[3],
           starreal prod[3])
{
    prod[0] = u[1]*v[2] - u[2]*v[1];
    prod[1] = u[2]*v[0] - u[0]*v[2];
    prod[2] = u[0]*v[1] - u[1]*v[0];
}

/* scale a vector by a constant */
void vscale(starreal scale,
            starreal v[3],            
            starreal scaled[3])
{
    scaled[0] = v[0] * scale;
    scaled[1] = v[1] * scale;
    scaled[2] = v[2] * scale;
}

/* add two vectors u and v */
void vadd(starreal u[3],
          starreal v[3],
          starreal sum[3])
{
    sum[0] = u[0] + v[0];
    sum[1] = u[1] + v[1];
    sum[2] = u[2] + v[2];
}

/* subtract two vectors u and v */
void vsub(const starreal u[3],
          const starreal v[3],
          starreal sum[3])
{
    sum[0] = u[0] - v[0];
    sum[1] = u[1] - v[1];
    sum[2] = u[2] - v[2];
}

/* copy one vector's values into another */
void vcopy(starreal u[3],
           starreal v[3])
{
    v[0] = u[0];
    v[1] = u[1];
    v[2] = u[2];
}

/* return the length of a vector */
starreal vlength(starreal u[3])
{
    return sqrt(u[0]*u[0] + u[1]*u[1] + u[2]*u[2]);
}

/* return if u and v are the same vector, false otherwise */
bool vequal(starreal u[3],
            starreal v[3])
{
    return (u[0] == v[0]) && (u[1] == v[1]) && (u[2] == v[2]);
}

/* compute the euclidean distance between two points u and v */
starreal vdist(starreal u[3],
             starreal v[3])
{
    starreal diff[3];
    vsub(u, v, diff);
    return vlength(diff);
}

/* project the vector u onto the vector v */
void vproject(starreal u[3],
              starreal v[3],
              starreal vout[3])
{
    starreal dotprod = dot(u,v);
    starreal length = vlength(v);
    if (length > 0)
    {
        vscale(dotprod / length, v, vout);
    }
    else
    {
        vscale(0.0, v, vout);
    }
}

/* project the vector v onto the plane through the origin with normal n */
void vprojecttoplane(starreal v[3],
                     starreal n[3],
                     starreal vout[3])
{
    starreal proj[3];
    vproject(v,n,proj);
    vsub(v,proj,vout);
}

<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkUnstructuredGridCenterlineGroupsClipper.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkUnstructuredGridCenterlineGroupsClipper.h,v $
Language:  C++
Date:      Sun Feb 20 15:29:37 CET 2011
Version:   Revision: 1.0

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkUnstructuredGridCenterlineGroupsClipper - Split an unstructured grid into groups/branches corresponding to their proximity to the polyball line of a branched centerline. 
// .SECTION Description
// ..

#ifndef __vtkvmtkUnstructuredGridCenterlineGroupsClipper_h
#define __vtkvmtkUnstructuredGridCenterlineGroupsClipper_h

#include "vtkUnstructuredGridAlgorithm.h"
#include "vtkUnstructuredGrid.h"
#include "vtkPolyData.h"
#include "vtkIdList.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkUnstructuredGridCenterlineGroupsClipper : public vtkUnstructuredGridAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkUnstructuredGridCenterlineGroupsClipper,vtkUnstructuredGridAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkUnstructuredGridCenterlineGroupsClipper *New();
  
  vtkSetObjectMacro(Centerlines,vtkPolyData);
  vtkGetObjectMacro(Centerlines,vtkPolyData);

  vtkSetObjectMacro(CenterlineGroupIds,vtkIdList);
  vtkGetObjectMacro(CenterlineGroupIds,vtkIdList);

  vtkSetStringMacro(CenterlineGroupIdsArrayName);
  vtkGetStringMacro(CenterlineGroupIdsArrayName);

  vtkSetStringMacro(CenterlineRadiusArrayName);
  vtkGetStringMacro(CenterlineRadiusArrayName);

  vtkSetStringMacro(GroupIdsArrayName);
  vtkGetStringMacro(GroupIdsArrayName);

  vtkSetStringMacro(BlankingArrayName);
  vtkGetStringMacro(BlankingArrayName);

  vtkSetMacro(ClipAllCenterlineGroupIds,int);
  vtkGetMacro(ClipAllCenterlineGroupIds,int);
  vtkBooleanMacro(ClipAllCenterlineGroupIds,int);

  vtkSetMacro(GenerateClippedOutput,int);
  vtkGetMacro(GenerateClippedOutput,int);
  vtkBooleanMacro(GenerateClippedOutput,int);

  vtkUnstructuredGrid* GetClippedOutput();
  
  vtkSetMacro(CutoffRadiusFactor,double);
  vtkGetMacro(CutoffRadiusFactor,double);

  vtkSetMacro(ClipValue,double);
  vtkGetMacro(ClipValue,double);

  vtkSetMacro(UseRadiusInformation,int);
  vtkGetMacro(UseRadiusInformation,int);
  vtkBooleanMacro(UseRadiusInformation,int);

  protected:
  vtkvmtkUnstructuredGridCenterlineGroupsClipper();
  ~vtkvmtkUnstructuredGridCenterlineGroupsClipper();

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  vtkPolyData* Centerlines;

  vtkIdList* CenterlineGroupIds;

  char* CenterlineGroupIdsArrayName;
  char* CenterlineRadiusArrayName;

  char* GroupIdsArrayName;
  char* BlankingArrayName;

  int ClipAllCenterlineGroupIds;
  double CutoffRadiusFactor;
  double ClipValue;

  int GenerateClippedOutput;

  int UseRadiusInformation;

  private:
  vtkvmtkUnstructuredGridCenterlineGroupsClipper(const vtkvmtkUnstructuredGridCenterlineGroupsClipper&);  // Not implemented.
  void operator=(const vtkvmtkUnstructuredGridCenterlineGroupsClipper&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Misc/vtkvmtkMeshWallShearRate.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkMeshWallShearRate.h,v $
Language:  C++
Date:      $Date: 2006/07/27 08:28:36 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkMeshWallShearRate - calculates wall shear rate from velocity components in a mesh
// .SECTION Description
// .

#ifndef __vtkvmtkMeshWallShearRate_h
#define __vtkvmtkMeshWallShearRate_h

#include "vtkPolyDataAlgorithm.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_MISC_EXPORT vtkvmtkMeshWallShearRate : public vtkPolyDataAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkMeshWallShearRate,vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkMeshWallShearRate *New();

  vtkSetStringMacro(VelocityArrayName);
  vtkGetStringMacro(VelocityArrayName);
 
  vtkSetStringMacro(WallShearRateArrayName);
  vtkGetStringMacro(WallShearRateArrayName);
 
  vtkSetMacro(ComputeIndividualPartialDerivatives,int);
  vtkGetMacro(ComputeIndividualPartialDerivatives,int);
  vtkBooleanMacro(ComputeIndividualPartialDerivatives,int);

  vtkSetMacro(UseFullStrainRateTensor,int);
  vtkGetMacro(UseFullStrainRateTensor,int);
  vtkBooleanMacro(UseFullStrainRateTensor,int);

  vtkSetMacro(ConvergenceTolerance,double);
  vtkGetMacro(ConvergenceTolerance,double);

  vtkSetMacro(QuadratureOrder,int);
  vtkGetMacro(QuadratureOrder,int);

  protected:
  vtkvmtkMeshWallShearRate();
  ~vtkvmtkMeshWallShearRate();  

  int FillInputPortInformation(int, vtkInformation *info) VTK_OVERRIDE;
  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  char* VelocityArrayName;
  char* WallShearRateArrayName;

  int ComputeIndividualPartialDerivatives;

  double ConvergenceTolerance;
  int QuadratureOrder;
  int UseFullStrainRateTensor;

  private:
  vtkvmtkMeshWallShearRate(const vtkvmtkMeshWallShearRate&);  // Not implemented.
  void operator=(const vtkvmtkMeshWallShearRate&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkItems.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkItems.cxx,v $
  Language:  C++
  Date:      $Date: 2005/11/15 17:39:25 $
  Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkItems.h"

#include "vtkObjectFactory.h"
#include "vtkIdList.h"
#include "vtkCell.h"



vtkvmtkItems::~vtkvmtkItems()
{
  if ( this->Array != NULL )
    {
    this->ReleaseArray();

    delete [] this->Array;
    this->Array = NULL;
    }
}

void vtkvmtkItems::Allocate(vtkIdType sz, vtkIdType ext)
{
  if ( this->Array != NULL )
    {
    this->ReleaseArray();
    delete [] this->Array;
    this->Array = NULL;
    }

  this->Size = sz;
  this->Array = new vtkvmtkItem*[sz];
  this->Extend = ext;
  this->MaxId = -1;

  for (vtkIdType i=0; i<sz; i++)
    {
    this->Array[i] = InstantiateNewItem(this->ItemType);
    }
}

void vtkvmtkItems::AllocateItem(vtkIdType i, vtkIdType itemType)
  {
  this->Array[i]->Delete();
  this->Array[i] = InstantiateNewItem(itemType);
  }

void vtkvmtkItems::ReleaseArray()
  {
  for (vtkIdType i=0; i<this->Size; i++)
    {
    this->Array[i]->UnRegister(this);
    }
  }

void vtkvmtkItems::Squeeze()
  {
  this->Resize (this->MaxId+1);
  }

void vtkvmtkItems::Reset()
  {
  this->MaxId = -1;
  }

void vtkvmtkItems::Initialize()
  {
  this->Reset();
  this->Squeeze();
  }

vtkvmtkItem **vtkvmtkItems::Resize(vtkIdType sz)
{
  vtkIdType i;
  vtkvmtkItem** newArray;
  vtkIdType newSize;

  if ( sz >= this->Size )
    {
    newSize = this->Size + sz;
    }
  else
    {
    newSize = sz;
    }

  newArray = new vtkvmtkItem*[newSize];

  for (i=0; i<sz && i<this->Size; i++)
    {
    newArray[i] = this->Array[i];
    }

  for (i=this->Size; i<newSize ; i++)
    {
    newArray[i] = this->InstantiateNewItem(this->ItemType);
    }

  this->Size = newSize;
  delete [] this->Array;
  this->Array = newArray;

  return NULL;
}

void vtkvmtkItems::DeepCopy(vtkvmtkItems *src)
  {
  vtkIdType i, numItems;

  numItems = src->GetNumberOfItems();

  this->Allocate(src->Size, src->Extend);
  for (i=0; i<numItems; i++)
    {
    this->GetItem(i)->DeepCopy(src->GetItem(i));
    }

  this->MaxId = src->MaxId;
  }

void vtkvmtkItems::ShallowCopy(vtkvmtkItems *src)
  {
  if ( this->Array != NULL )
    {
    this->ReleaseArray();
    delete [] this->Array;
    this->Array = NULL;
    }

  this->Array = new vtkvmtkItem*[src->Size];

  for (vtkIdType i=0; i<src->Size; i++)
    {
    this->Array[i] = src->Array[i];
    this->Array[i]->Register(this);
    }

  this->MaxId = src->MaxId;
  this->Extend = src->Extend;
  this->Size = src->Size;
  }


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/journal.c<|end_filename|>
/*****************************************************************************/
/*             Global journal and helper functions                           */
/*****************************************************************************/
/* improvement journal entry. this should be general enough
   to store information on any change to the mesh, and for each
   change should store enough information to invert it */
   
enum journalentryclasses
{
    ALLENTRIES,    /* match all entries */
    INSERTDELETE,  /* insertion or deletion of vertices */
    SMOOTH,        /* change position of a single vertex */
    TOPOLOGICAL,   /* topological change involving multiple vertices */
    LABEL          /* classify a vertex */
};

enum journalentrytypes
{
    INSERTVERTEX,  /* insertion of a vertex */
    DELETEVERTEX,  /* deletion of a vertex */
    SMOOTHVERTEX,  /* smoothing of a vertex */
    DELETETET,     /* single tet deletion */
    INSERTTET,     /* single tet insertion */
    FLIP23,        /* 2-3 flip, base case for face removal */
    FLIP32,        /* 3-2 flip, base case for edge removal */
    FLIP22,        /* 2-2 flip */
    FLIP41,        /* 4-1 flip (precedes deletion of interior vertex) */
    FLIP14,        /* 1-4 flip (follows insertion of interior vertex) */
    FLIP13,        /* 1-3 flip (same as 1-4 but inserted vertex is on facet) */
    FLIP31,        /* the inverse of a 1-3 flip */
    FLIP12,        /* 1-2 flip (same as 1-4 but inserted vertex is on edge) */
    FLIP21,        /* inverse of 1-2 */
    CLASSIFY       /* classify vertex (FREEVERTEX, FACETVERTEX, etc) */
};

struct journalentry
{
    int id;             /* unique identifier for this entry */
    int class;          /* class (smoothing, topological, etc) */
    int type;           /* type of entry, selected from jounalentrytypes */
    tag verts[5];       /* up to five vertices involved in the operation */
    int numverts;       /* the exact number involved in the operation, or the type (for classify)*/
    starreal newpos[3]; /* the new position of the vertex, if it was smoothed */  
    starreal oldpos[3]; /* the old position of the vertex, if it was moved */
};

/* GLOBAL */
struct arraypoolstack* journal;
struct arraypoolstack journalstack;

/* print a single journal entry */
void printjournalentry(struct journalentry *entry)
{
    switch (entry->type)
    {
        case INSERTVERTEX:
            printf("(ID: %d) Inserted new vertex %d\n", entry->id, (int) entry->verts[0]);
            break;
        case SMOOTHVERTEX:
            printf("(ID: %d) Smoothed vertex %d from (%g %g %g) to (%g %g %g)\n", entry->id, (int) entry->verts[0], entry->oldpos[0], entry->oldpos[1], entry->oldpos[2], entry->newpos[0], entry->newpos[1], entry->newpos[2]);
            break;
        case INSERTTET:
            printf("(ID: %d) Inserted tet (v1=%d, v2=%d, v3=%d, v4=%d)\n", entry->id, (int) entry->verts[0],
                                                                                      (int) entry->verts[1],
                                                                                      (int) entry->verts[2],
                                                                                      (int) entry->verts[3]);
            break;
        case DELETETET:
            printf("(ID: %d) Deleted tet (v1=%d, v2=%d, v3=%d, v4=%d)\n", entry->id, (int) entry->verts[0],
                                                                                      (int) entry->verts[1],
                                                                                      (int) entry->verts[2],
                                                                                      (int) entry->verts[3]);
            break;
        case FLIP23:
            printf("(ID: %d) Performed 2-3 flip on submesh (v1=%d, v2=%d, v3=%d, vbot=%d, vtop=%d)\n", entry->id, (int) entry->verts[0],
                                                                                              (int) entry->verts[1],
                                                                                              (int) entry->verts[2],
                                                                                              (int) entry->verts[3],
                                                                                              (int) entry->verts[4]);
            break;
        case FLIP22:
            printf("(ID: %d) Performed 2-2 flip on submesh (v1=%d, v2=%d, v3=%d, vbot=%d, vtop=%d)\n", entry->id, (int) entry->verts[0],
                                                                                              (int) entry->verts[1],
                                                                                              (int) entry->verts[2],
                                                                                              (int) entry->verts[3],
                                                                                              (int) entry->verts[4]);
            break;
        case FLIP32:
            printf("(ID: %d) Performed 3-2 flip on submesh (v1=%d, v2=%d, v3=%d, vbot=%d, vtop=%d)\n", entry->id, (int) entry->verts[0],
                                                                                              (int) entry->verts[1],
                                                                                              (int) entry->verts[2],
                                                                                              (int) entry->verts[3],
                                                                                              (int) entry->verts[4]);
            break;
        case FLIP14:
            printf("(ID: %d) Performed 1-4 flip on submesh (v1=%d, v2=%d, v3=%d, v4=%d, vfacet=%d)\n", entry->id, (int) entry->verts[0],
                                                                                              (int) entry->verts[1],
                                                                                              (int) entry->verts[2],
                                                                                              (int) entry->verts[3],
                                                                                              (int) entry->verts[4]);
            break;
        case FLIP13:
            printf("(ID: %d) Performed 1-3 flip on submesh (v1=%d, v2=%d, v3=%d, v4=%d, vfacet=%d)\n", entry->id, (int) entry->verts[0],
                                                                                              (int) entry->verts[1],
                                                                                              (int) entry->verts[2],
                                                                                              (int) entry->verts[3],
                                                                                              (int) entry->verts[4]);
            break;
        case FLIP12:
            printf("(ID: %d) Performed 1-3 flip on submesh (v1=%d, v2=%d, v3=%d, v4=%d, vfacet=%d)\n", entry->id, (int) entry->verts[0],
                                                                                              (int) entry->verts[1],
                                                                                              (int) entry->verts[2],
                                                                                              (int) entry->verts[3],
                                                                                              (int) entry->verts[4]);
            break;
        case CLASSIFY:
            printf("(ID %d) Assigned vertex %d type %d\n", entry->id, (int) entry->verts[0], entry->numverts);
            break;
        default:
            printf("(ID %d) I don't know the journal entry type %d\n", entry->id, entry->type);
    }
}

/* print a single journal entry */
void printjournalentrystream(FILE* o, struct journalentry *entry, int index)
{
    int i;
    
    /* first print the ID of the operation */
    fprintf(o, "%d ", index);
    
    /* now print the type */
    switch (entry->type)
    {
        case INSERTVERTEX:
            fprintf(o,"INSERTVERTEX ");
            break;
        case SMOOTHVERTEX:
            fprintf(o,"SMOOTHVERTEX ");
            break;
        case INSERTTET:
            fprintf(o,"INSERTTET ");
            break;
        case DELETETET:
            fprintf(o,"DELETETET ");
            break;
        case FLIP23:
            fprintf(o,"FLIP23 ");
            break;
        case FLIP22:
            fprintf(o,"FLIP22 ");
            break;
        case FLIP32:
            fprintf(o,"FLIP32 ");
            break;
        case FLIP14:
            fprintf(o,"FLIP14 ");
            break;
        case FLIP13:
            fprintf(o,"FLIP13 ");
            break;
        case FLIP12:
            fprintf(o,"FLIP12 ");
            break;
        case CLASSIFY:
            fprintf(o,"CLASSIFY ");
            break;
        default:
            printf("(ID %d) I don't know the journal entry type %d\n", entry->id, entry->type);
            starexit(1);
    }
    
    /* number of vertices involved in the operation */
    fprintf(o, "%d ", entry->numverts);
    
    /* the tags of these vertices 
       (NB these are different from the vertex numbers in output) */
    for (i=0; i<entry->numverts; i++)
    {
        fprintf(o, "%d ", (int) entry->verts[i]);
    }
    
    /* if this is a smooth or insert, print the new vertex position */
    if ((entry->type == SMOOTHVERTEX) || (entry->type == INSERTVERTEX))
    {
        fprintf(o, "%.18g %.18g %1.8g ", entry->newpos[0], entry->newpos[1], entry->newpos[2]);
    }
    
    /* end the line */
    fprintf(o, "\n");
}

/* return the ID of the most recent journal entry */
int lastjournalentry(void)
{
    return ((struct journalentry *) arraypoolfastlookup(&(journal->pool), (unsigned long) journal->top))->id;
}

/* copy the top fromtop elements from one stack to another */
void copyjournaltop(struct arraypoolstack *fromstack,
                    struct arraypoolstack *tostack,
                    int fromtop)
{
    struct journalentry *fromentry, *toentry;
    int i;
    
    /* reset the to stack */
    stackrestart(tostack);
    
    /* copy fromtop -> top */
    for (i=fromtop; i<=fromstack->top; i++)
    {
        /* get the right tet out of stack */
        fromentry = (struct journalentry *) arraypoolfastlookup(&(fromstack->pool), (unsigned long) i);
        toentry = (struct journalentry *) stackpush(tostack);
        
        /* copy it over */
        memcpy(toentry, fromentry, sizeof(struct journalentry));
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("copied top of stack\n");
        for (i=0; i<10; i++)
        {
            fromentry = (struct journalentry *) arraypoolfastlookup(&(fromstack->pool), (unsigned long) fromstack->top - i);
            toentry = (struct journalentry *) arraypoolfastlookup(&(tostack->pool), (unsigned long) tostack->top - i);
            printf("[%d] fromentry %d toentry %d\n", i, fromentry->id, toentry->id);
        }
        printf("fromstack->top / 2 = %d, tostack->top = %d\n", (int) fromstack->top / 2, (int) tostack->top);
    }
    
    assert(fromstack->top / 2 == tostack->top - 1 || fromstack->top / 2 == tostack->top);
}

/* chop the journal down to half its current size */
void chopjournal(void)
{
    struct arraypoolstack newjournal;
    stackinit(&newjournal, sizeof(struct journalentry));
    
    if (improvebehave.verbosity > 5)
    {
        printf("halving stack from %d to %d elements\n", (int) journal->top, (int) journal->top / 2);
    }
    
    /* copy the top half of the elements */
    copyjournaltop(journal, &newjournal, journal->top / 2);
    
    /* free the old stack */
    stackdeinit(journal);
    
    /* copy the new stack to the old stack */
    memcpy(journal, &newjournal, sizeof(struct arraypoolstack));
}

/* insert the record of an improvement action in the journal */
void insertjournalentry(struct tetcomplex * mesh,
                        int type,
                        tag verts[],
                        int numverts,
                        starreal oldpos[],
                        starreal newpos[])
{
    struct journalentry* entry;
    int i;
    
    /* if journal is getting too big, chop it in half */
    if (journal->top > JOURNALHALFSIZE)
    {
        chopjournal();
    }
    
    /* create a new journal entry on the top of the stack */
    entry = (struct journalentry *) stackpush(journal);    
    /* give this entry a unique id */
    entry->id = maxjournalid++;
    /* assign the type */
    entry->type = type;
    /* copy vertices */
    entry->numverts = numverts;
    for (i=0; i<numverts; i++)
    {
        entry->verts[i] = verts[i];
    }
    
    /* type specific stuff */
    switch (type)
    {
        case SMOOTHVERTEX:
            /* copy previous and new vertex location */
            vcopy(oldpos, entry->oldpos);
            vcopy(newpos, entry->newpos);
            entry->class = SMOOTH;
            break;
        case INSERTTET:
            entry->class = TOPOLOGICAL;
        case DELETETET:
            entry->class = TOPOLOGICAL;
        case FLIP23:
            entry->class = TOPOLOGICAL;
            break;
        case FLIP22:
            entry->class = TOPOLOGICAL;
            break;
        case FLIP32:
            entry->class = TOPOLOGICAL;
            break;
        case FLIP13:
            entry->class = TOPOLOGICAL;
            break;
        case FLIP12:
            entry->class = TOPOLOGICAL;
            break;
        case FLIP14:
            entry->class = TOPOLOGICAL;
            break;
        case FLIP41:
            entry->class = TOPOLOGICAL;
            break;
        case INSERTVERTEX:
            /* copy initial vertex position */
            vcopy(newpos, entry->newpos);
            entry->class = INSERTDELETE;
            /* force set the new vertex's type to INPUTVERTEX */
            /* because we're about to classify it */
            ((struct vertextype *) arraypoolforcelookup(&vertexinfo, verts[0]))->kind = INPUTVERTEX;
            break;
        case CLASSIFY:
            entry->class = LABEL;
            /* copy newpos, which encodes constraining vector of facet or segment */
            vcopy(newpos, entry->newpos);
            break;
        default:
            printf("I don't know the journal entry type %d\n", entry->type);
            starexit(1);
    };
    
    if (improvebehave.verbosity > 5)
    {
        printf("Now adding the following entry:");
        printjournalentry(entry);
    }
}

/* playback a single journal entry */
void playbackjournalentry(struct tetcomplex * mesh,
                        struct journalentry *entry)
{
    starreal* pos;
    tag newtag;
    struct vertextype *info;
    struct vertex *newvertex;         /* pointer to newly allocated vertex */
    
    if (improvebehave.verbosity > 4)
    {
        printf("Now playing back the following entry:\n");
        printjournalentry(entry);
    }
    
    switch (entry->type)
    {
        case SMOOTHVERTEX:
            /* to playback a smooth, move the vertex to where it was smoothed */
            /* fetch the vertex position */
            pos = ((struct vertex *) tetcomplextag2vertex(mesh, entry->verts[0]))->coord;
            /* replace it with the new value */
            vcopy(entry->newpos, pos);
            
            break;
        case INSERTTET:
            inserttet(mesh,
                      entry->verts[0],
                      entry->verts[1],
                      entry->verts[2],
                      entry->verts[3],
                      false);
            break;
        case DELETETET:
            deletetet(mesh,
                      entry->verts[0],
                      entry->verts[1],
                      entry->verts[2],
                      entry->verts[3],
                      false);
            break;
        case FLIP23:
            flip23(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case FLIP22:
            flip22(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case FLIP32:
            flip32(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case FLIP13:
            flip13(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case FLIP12:
            flip12(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case FLIP14:
            flip14(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case FLIP41:
            flip41(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case INSERTVERTEX:
            /* allocate the new vertex */
            newtag = proxipoolnew(mesh->vertexpool, 0, (void **) &newvertex);
            /* make sure it has the right ID according to the journal */
            assert(newtag == entry->verts[0]);
            break;
        case CLASSIFY:
            /* fetch vertex info structure */
            info = (struct vertextype *) arraypoolforcelookup(&vertexinfo, entry->verts[0]);
            /* set the vertex type, which is encoded in numverts */
            info->kind = entry->numverts;
            /* copy the facet or segment vector, encoded in newpos */
            vcopy(entry->newpos, info->vec);
        default:
            printf("I don't know the journal entry type %d\n", entry->type);
            starexit(1);
    };
}


/* invert a single journal entry */
void invertjournalentry(struct tetcomplex * mesh,
                        struct journalentry *entry)
{
    starreal* pos;
    
    if (improvebehave.verbosity > 5)
    {
        printf("Now inverting the following entry:\n");
        printjournalentry(entry);
    }
    
    switch (entry->type)
    {
        case SMOOTHVERTEX:
            /* to invert a smooth, just put the vertex back where it came from */
            /* fetch the vertex position */
            pos = ((struct vertex *) tetcomplextag2vertex(mesh, entry->verts[0]))->coord;
            /* replace it with the old value */
            vcopy(entry->oldpos, pos);
            
            break;
        case INSERTTET:
            /* to invert an insertion, perform a deletion */
            deletetet(mesh,
                      entry->verts[0],
                      entry->verts[1],
                      entry->verts[2],
                      entry->verts[3],
                      false);
            break;
        case DELETETET:
            /* to invert a deletion, perform an insertion */
            inserttet(mesh,
                      entry->verts[0],
                      entry->verts[1],
                      entry->verts[2],
                      entry->verts[3],
                      false);
            break;
        case FLIP23:
            /* to invert a 2-3 flip, perform a 3-2 flip on the same submesh */
            flip32(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case FLIP22:
            /* to invert a 2-2 flip, we perform another 2-2 flip, 
               but we need to reorder the vertices. the order of
               the verts in the journal entry are (from the pre-flip
               perspective) (1,2,3,bot,top), with the flip on the 1-2
               edge. To reverse the flip we do
               (bot, top, 3, 2, 1) */
            flip22(mesh,
                   entry->verts[3],
                   entry->verts[4],
                   entry->verts[2],
                   entry->verts[1],
                   entry->verts[0],
                   false);
            break;
        case FLIP32:
            /* to invert a 3-2 flip, perform a 2-3 flip on the same submesh */
            flip23(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case FLIP13:
            /* to invert a 1-3 flip, perform a 3-1 flip on the same submesh */
            flip31(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case FLIP12:
            /* to invert a 1-2 flip, perform a 2-1 flip on the same submesh */
            flip21(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case FLIP14:
            /* to invert a 1-4 flip, perform a 4-1 flip on the same submesh */
            flip41(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case FLIP41:
            /* to invert a 1-4 flip, perform a 4-1 flip on the same submesh */
            flip14(mesh,
                   entry->verts[0],
                   entry->verts[1],
                   entry->verts[2],
                   entry->verts[3],
                   entry->verts[4],
                   false);
            break;
        case INSERTVERTEX:
            /* mark this vertex as dead so it won't be output... */
            ((struct vertextype *) arraypoolforcelookup(&vertexinfo, entry->verts[0]))->kind = DEADVERTEX;            
            /*
            vertexptr = (struct vertex *) proxipooltag2object(vertexpoolptr, entry->verts[0]);
            vertexptr->kind = DEADVERTEX;
            proxipoolfree(mesh->vertexpool, entry->verts[0]);
            */
            /* free the memory from the vertex info structure */
            /*
            arraypoolfreeindex(&vertexinfo, entry->verts[0]);
            */
            break;
        case CLASSIFY:
            /* for now, don't do anything for a classify TODO: should i do something here? */
            break;
        default:
            printf("I don't know the journal entry type %d\n", entry->type);
            starexit(1);
    };
}

/* invert the last numentries journal entries */
void invertjournaltop(struct tetcomplex *mesh,
                      int numentries)
{
    int i;
    struct journalentry *entry;
    
    if (improvebehave.verbosity > 5)
    {
        printf("Inverting the last %d entries of the journal.\n", numentries
        );
    }
    
    for (i=0; i<numentries; i++)
    {
        if (journal->top != STACKEMPTY)
        {
            entry = (struct journalentry *) stackpop(journal);
            invertjournalentry(mesh,entry);
        }
        else
        {
            printf("Journal empty, so not inverting any more entries. Removed %d before bailing.\n", i);
            break;
        }
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("done.\n");
    }
}

/* invert all the journal entries up to (but not including) the one
   with id 'id' */
void invertjournalupto(struct tetcomplex* mesh,
                       int id)
{
    int i=0;
    struct journalentry *entry;
    
    while(journal->top - i >= 0)
    {
        /* peek at the next on down the stack */
        entry = (struct journalentry *) arraypoolfastlookup(&(journal->pool), (unsigned long) journal->top - i);
        /* if this is the one we're looking for, invert all entries up to it */
        if (entry->id == id)
        {
            invertjournaltop(mesh, i);
            return;
        } 
        
        /* look deeper next time */
        i++;
    }
    
    printf("Error: trying to invert journal up to entry id %d but it wasn't found...\n", id);
    starexit(1);
}

/* figure out number of ops and start, end indices for given id range */
void journalrangetoindex(int startid, 
                        int endid,
                        int *startindex,
                        int *endindex,
                        int *numops)
{
    int i = startid;
    struct journalentry *entry;
    bool foundend = false;
    bool foundstart = false;
    
    /* find the first entry */
    i = 0;
    while (foundend == false || foundstart == false)
    {
        /* peek at the next on down the stack */
        entry = (struct journalentry *) arraypoolfastlookup(&(journal->pool), (unsigned long) journal->top - i);
        
        /* is this the id we're looking for? */
        if (entry->id == startid)
        {
            *startindex = journal->top - i;
            foundstart = true;
        }
        if (entry->id == endid)
        {
            *endindex = journal->top - i;
            foundend = true;
        }
        
        i++;
    }
    
    *numops = (*endindex) - (*startindex);
    
    if (improvebehave.verbosity > 4)
    {
        printf("startindex = %d, endindex = %d, numops = %d\n", *startindex, *endindex, *numops);
    }
}

/* print out a range of journal entries to the specified stream */
void printjournalrangestream(FILE *o, int startindex, int endindex)
{
    int i;
    struct journalentry *entry;
    
    for (i=startindex+1; i<=endindex; i++)
    {
        if (i <= lastjournalentry())
        {
            entry = (struct journalentry *) arraypoolfastlookup(&(journal->pool), (unsigned long) i);
            printjournalentrystream(o, entry, i);
        }
        else
        {
            printf("tried to access journal entry %d, but lastjournalentry() is %d\n", i, lastjournalentry());
            starexit(1);
        }
    }
}

/* print out the top numentries entries from the journal */
void printjournaltop(int numentries)
{
    int i;
    struct journalentry *entry;
    
    printf("The last %d operations on the stack (from newest to oldest):\n", numentries);
    
    for (i=0; i<numentries; i++)
    {
        if ((journal->top - i) >= 0)
        {
            entry = (struct journalentry *) arraypoolfastlookup(&(journal->pool), (unsigned long) journal->top - i);
            printjournalentry(entry);
        }
        else
        {
            printf("Journal empty.\n");
            break;
        }
    }
}

/* find and return the last journal entry that involved vtx */
struct journalentry* findjournalentryvertex(tag vtx, int entryclass)
{
    int i=0, j;
    struct journalentry *entry;
    
    while(journal->top - i >= 0)
    {
        /* peek at the next on down the stack */
        entry = (struct journalentry *) arraypoolfastlookup(&(journal->pool), (unsigned long) journal->top - i);
        
        /* check each of the vertices that this entry affected */
        if (((entry->class == entryclass) || (entryclass == ALLENTRIES)) &&
            (entry->type != DELETETET))
        {
            for (j=0; j<entry->numverts; j++)
            {
                if (entry->verts[j] == vtx)
                {
                    return entry;
                }
            }
        }
        
        i++;
    }
    
    printf("Error: couldn't find an entry relating to vertex %d...\n", (int) vtx);
    starexit(1);
    return NULL;
}

/* given a vertex, return a tet that the vertex lies in.
   this assumes that the vertex has participated in some
   topological change to the mesh */
void findtetfromvertex(tetcomplex *mesh,
                        tag vtx,
                        tag outtet[4])
{
    /* first, locate a journal entry with this vertex */
    struct journalentry* entry = findjournalentryvertex(vtx, TOPOLOGICAL);
    tag tets[4][4]; /* the tets that existed after this entry */
    int numtets;    /* the number of tets that existed after this entry */
    int i,j;
    
    switch (entry->type)
    {
        case INSERTTET:
            /* to get coverage, just need single tet */
            numtets = 1;
            /* (top, 1, 2, bot) */
            tets[0][0] = entry->verts[0];
            tets[0][1] = entry->verts[1];
            tets[0][2] = entry->verts[2];
            tets[0][3] = entry->verts[3];
            
            break;
        case FLIP23:
            /* for a 2-3 flip, the 5 verts are (1,2,3,bot,top) */
            /* to get coverage over all 5 verts, only need 2 tets */
            numtets = 2;
            /* (top, 1, 2, bot) */
            tets[0][0] = entry->verts[4];
            tets[0][1] = entry->verts[0];
            tets[0][2] = entry->verts[1];
            tets[0][3] = entry->verts[3];
            
            /* (top, 2, 3, bot) */
            tets[1][0] = entry->verts[4];
            tets[1][1] = entry->verts[1];
            tets[1][2] = entry->verts[2];
            tets[1][3] = entry->verts[3];
            
            break;
        case FLIP22:
            /* for a 2-2 flip, the 5 verts are (1,2,3,bot,top) */
            /* to get coverage over all 5 verts, only need 2 tets */
            numtets = 2;
            /* (3, 1, top, bot) */
            tets[0][0] = entry->verts[2];
            tets[0][1] = entry->verts[0];
            tets[0][2] = entry->verts[4];
            tets[0][3] = entry->verts[3];
            
            /*  (3, 2, bot, top) */
            tets[1][0] = entry->verts[2];
            tets[1][1] = entry->verts[1];
            tets[1][2] = entry->verts[3];
            tets[1][3] = entry->verts[4];
            
            break;
        case FLIP32:
            /* for a 3-2 flip, the 5 verts are (1,2,3,bot,top) */
            /* to get coverage over all 5 verts, only need 2 tets */
            numtets = 2;
            
            /* (top, 1, 2, bot) */
            tets[0][0] = entry->verts[4];
            tets[0][1] = entry->verts[0];
            tets[0][2] = entry->verts[1];
            tets[0][3] = entry->verts[2];

            /* (top, 2, 3, bot) */
            tets[1][0] = entry->verts[3];
            tets[1][1] = entry->verts[2];
            tets[1][2] = entry->verts[1];
            tets[1][3] = entry->verts[0];

            break;
        case FLIP14:
            /* for a 1-4 flip, the 5 verts are (1,2,3,4,body) */
            /* to get coverage over all 5 verts, only need 2 tets */
            numtets = 2;
            /* (1, 2, 3, b) */
            tets[0][0] = entry->verts[0];
            tets[0][1] = entry->verts[1];
            tets[0][2] = entry->verts[2];
            tets[0][3] = entry->verts[4];
            
            /* (1, 3, 4, b) */
            tets[1][0] = entry->verts[0];
            tets[1][1] = entry->verts[2];
            tets[1][2] = entry->verts[3];
            tets[1][3] = entry->verts[4];
            
            break;
        case FLIP13:
            /* for a 1-3 flip, the 5 verts are (1,2,3,4,face) */
            /* to get coverage over all 5 verts, only need 2 tets */
            numtets = 2;
            
            /* (1, 2, 3, b) */
            tets[0][0] = entry->verts[0];
            tets[0][1] = entry->verts[1];
            tets[0][2] = entry->verts[4];
            tets[0][3] = entry->verts[3];
            
            /* (1, 3, 4, b) */
            tets[1][0] = entry->verts[0];
            tets[1][1] = entry->verts[1];
            tets[1][2] = entry->verts[2];
            tets[1][3] = entry->verts[4];
            
            break;
        case FLIP12:
            /* for a 1-2 flip, the 5 verts are (1,2,3,4,segment) */
            /* to get coverage over all 5 verts, only need 2 tets */
            numtets = 2;
            
            /* (1, 3, 4, s) */
            tets[0][0] = entry->verts[0];
            tets[0][1] = entry->verts[2];
            tets[0][2] = entry->verts[3];
            tets[0][3] = entry->verts[4];
            
            /* (2, 4, 3, s) */
            tets[1][0] = entry->verts[1];
            tets[1][1] = entry->verts[3];
            tets[1][2] = entry->verts[2];
            tets[1][3] = entry->verts[4];
            
            break;
        default:
            numtets = 0;
            printf("In findtetfromvertex I don't know the journal entry type %d\n", entry->type);
            starexit(1);
    }
    
    /* now, find a tet that contains the vertex */
    for (i=0; i<numtets; i++)
    {
        for (j=0; j<4; j++)
        {
            /* if the vertices match */
            if (tets[i][j] == vtx)
            {
                /* permute this tet so vtx is at the start */
                if (j == 0)
                {
                    outtet[0] = tets[i][0];
                    outtet[1] = tets[i][1];
                    outtet[2] = tets[i][2];
                    outtet[3] = tets[i][3];
                }
                else
                {
                    /* one swap (0,j)*/
                    outtet[0] = vtx;
                    outtet[j] = tets[i][0];
                    /* two swaps, same tet */
                    switch (j)
                    {
                        case 1:
                            outtet[3] = tets[i][2];
                            outtet[2] = tets[i][3];
                            break;
                        case 2:
                            outtet[1] = tets[i][3];
                            outtet[3] = tets[i][1];
                            break;
                        case 3:
                            outtet[1] = tets[i][2];
                            outtet[2] = tets[i][1];
                            break;
                    }
                }
                if (improvebehave.verbosity > 5)
                {
                    printf("the vertex is %d\n", (int) vtx);
                    printf("here is the operation:\n");
                    printjournalentry(entry);
                    printf("the tet we found is (%d %d %d %d)\n", (int) tets[i][0], (int) tets[i][1], (int) tets[i][2], (int) tets[i][3]);
                    printf("the tet we're returning is (%d %d %d %d)\n\n\n", (int) outtet[0], (int) outtet[1], (int) outtet[2], (int) outtet[3]);
                }
                assert(outtet[0] == vtx);
                /*
                assert(tetexists(mesh, outtet[0], outtet[1], outtet[2], outtet[3]));
                */
                return;
            }
        }
    }
    printf("wtf?!? we didn't find the vertex.\n");
    printf("the vertex is %d\n", (int) vtx);
    printf("here is the operation:\n");
    printjournalentry(entry);
    starexit(1);
}

/* write out current journal to a file  TODO this is unfinished...*/
void writejournal(struct behavior *b)
{
    char filename[300];
    FILE *outfile;
    int i=0, j;
    struct journalentry *entry;
    tag lverts[5] = {0, 0, 0, 0, 0};
    starreal lold[3] = {0.0, 0.0, 0.0};
    starreal lnew[3] = {0.0, 0.0, 0.0};
    
    /* copy over the input file name */
    strcpy(filename, b->innodefilename);
    
    /* if the filename currently has an extension, clip it off */
    if (filename[strlen(filename) - 5] == '.')
    {
        filename[strlen(filename) - 5] = '\0';
    }
    
    /* mention that this is the journal file */
    strcat(filename, ".journal");
    
    if (!b->quiet) 
    {
        printf("Writing out journal of %ld entries to %s.\n", journal->top, filename);
    }
    
    /* open the output file */
    outfile = fopen(filename, "w");
    if (outfile == (FILE *) NULL) 
    {
        printf("  Error:  Cannot create file %s.\n", filename);
        starexit(1);
    }
    
    /* first line: number of journal entries */
    fprintf(outfile, "%ld\n", journal->top);
    
    /* now print out each journal entry */
    for (i=0; i<=journal->top; i++)
    {
        /* fetch the ith journal entry */
        entry = (struct journalentry *) arraypoolfastlookup(&(journal->pool), (unsigned long) i);
        
        /* copy vertex tags to local with zero padding */
        for (j=0; j<entry->numverts; j++)
        {
            lverts[j] = entry->verts[j];
        }
        
        /* copy new position for smooths and inserts */
        if (entry->type == INSERTVERTEX || entry->type == SMOOTHVERTEX)
        {
            for (j=0; j<3; j++)
            {
                lnew[j] = entry->newpos[j];
            }
        }
        
        /* copy old position for smooths */
        if (entry->type == SMOOTHVERTEX)
        {
            for (j=0; j<3; j++)
            {
                lold[j] = entry->oldpos[j];
            }
        }
        
        /* print out the info for this entry */
        fprintf(outfile, "%d %d %d %d %d %d %d %d %d %g %g %g %g %g %g\n",
                entry->id,
                entry->class,
                entry->type,
                (int) lverts[0], (int) lverts[1], (int) lverts[2], (int) lverts[3], (int) lverts[4],
                entry->numverts,
                lnew[0], lnew[1], lnew[2],
                lold[0], lold[1], lold[2]);
    }
    
    /* close the file */
    fclose(outfile);
}

/* read a journal from a file  TODO unfinished...*/
void readjournal(char *journalfilename,
                 struct arraypoolstack *outjournal)
{
    /* char inputline[INPUTLINESIZE]; */ /* as string of maximum line size */
    /* char *stringptr; */               /* a pointer within the input */
    
    FILE *infile;
    
    /* Read the tetrahedra from an .ele file. */
    printf("Opening journal for reading: %s.\n", journalfilename);
    

    infile = fopen(journalfilename, "r");
    if (infile == (FILE *) NULL) 
    {
        printf("  Error:  Cannot access file %s.\n", journalfilename);
        starexit(1);
    }
}




<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataManifoldNeighborhood.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkPolyDataManifoldNeighborhood.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:46:44 $
Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataManifoldNeighborhood.h"

#include "vtkObjectFactory.h"
#include "vtkIdList.h"
#include "vtkCell.h"
#include "vtkMath.h"

  
vtkStandardNewMacro(vtkvmtkPolyDataManifoldNeighborhood);

void vtkvmtkPolyDataManifoldNeighborhood::Build()
{
  vtkIdType i, j, id;
  vtkIdType numCellsInStencil;
  vtkIdType startCell, nextCell;
  vtkIdType p1, p2;
  vtkIdType bp1, bp2;
  vtkIdType K;
  vtkIdType pointId;
  vtkIdList *cellIds, *ptIds, *stencilIds;
  vtkCell* cell;
  vtkPolyData* pdata = vtkPolyData::SafeDownCast(this->DataSet);

  if (pdata==NULL)
    {
    vtkErrorMacro(<< "Input data NULL or not poly data");
    }

  pointId = this->DataSetPointId;

  this->NPoints = 0;

  cellIds = vtkIdList::New();
  ptIds = vtkIdList::New();
  stencilIds = vtkIdList::New();

  pdata->GetPointCells (pointId, cellIds);
  numCellsInStencil = cellIds->GetNumberOfIds();
  if (numCellsInStencil < 1)
    {
    //          vtkWarningMacro("numCellsInStencil < 1: " << numCellsInStencil);
    cellIds->Delete();
    ptIds->Delete();
    stencilIds->Delete();
    return;
    }

  pdata->GetCellPoints(cellIds->GetId(0),ptIds);
  p2 = ptIds->GetId(0);
  i = 1;
  while (pointId == p2)
    {
    p2 = ptIds->GetId(i++);
    }

  pdata->GetCellEdgeNeighbors (-1,pointId,p2,cellIds);

  nextCell = cellIds->GetId(0);
  bp2 = -1;
  bp1 = p2;
  if (cellIds->GetNumberOfIds() == 1)
    {
    startCell = -1;
    }
  else
    {
    startCell = cellIds->GetId(1);
    }

  stencilIds->InsertNextId(p2);

  // walk around the stencil counter-clockwise and get cells
  for (j=0; j<numCellsInStencil; j++)
    {
    cell = pdata->GetCell(nextCell);
    p1 = -1;
    for (i = 0; i < 3; i++)
      {
      if ((p1 = cell->GetPointId(i)) != pointId && cell->GetPointId(i) != p2)
        {
        break;
        }
      }

    p2 = p1;
    stencilIds->InsertNextId (p2);
    pdata->GetCellEdgeNeighbors (nextCell, pointId, p2, cellIds);
    if (cellIds->GetNumberOfIds() != 1)
      {
      bp2 = p2;
      j++;
      break;
      }
    nextCell = cellIds->GetId(0);
    }

  // now walk around the other way. this will only happen if there
  // is a boundary cell left that we have not visited
  nextCell = startCell;
  p2 = bp1;
  for (; j<numCellsInStencil && startCell!=-1; j++)
    {
    cell = pdata->GetCell(nextCell);
    p1 = -1;
    for (i=0; i<3; i++)
      {
      if ((p1=cell->GetPointId(i))!=pointId && cell->GetPointId(i)!=p2)
        {
        break;
        }
      }
    p2 = p1;
    stencilIds->InsertNextId(p2);
    pdata->GetCellEdgeNeighbors (nextCell, pointId, p2, cellIds);
    if (cellIds->GetNumberOfIds() != 1)
      {
      bp1 = p2;
      break;
      }
    nextCell = cellIds->GetId(0);
    }

  if (bp2 != -1) // boundary edge
    {
    this->IsBoundary = true;
    id = stencilIds->IsId(bp2);
    for (i=0; i<=id/2; i++)
      {
      p1 = stencilIds->GetId(i);
      p2 = stencilIds->GetId(id-i);
      stencilIds->SetId(i,p2);
      stencilIds->SetId(id-i,p1);
      }
    }
  else
    {
    this->IsBoundary = false;
    K = stencilIds->GetNumberOfIds();
    // Remove last id. It's a duplicate of the first
    stencilIds->SetNumberOfIds(--K);
    }

  this->NPoints = stencilIds->GetNumberOfIds();
  if (this->PointIds!=NULL)
    {
    delete[] this->PointIds;
    this->PointIds = NULL;
    }
  this->PointIds = new vtkIdType[this->NPoints];
  memcpy(this->PointIds,stencilIds->GetPointer(0),this->NPoints*sizeof(vtkIdType));

  cellIds->Delete();
  ptIds->Delete();
  stencilIds->Delete();
}



<|start_filename|>vtkVmtk/Misc/vtkvmtkPolyDataNormalPlaneEstimator.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkPolyDataNormalPlaneEstimator.cxx,v $
Language:  C++
Date:      $Date: 2015/12/01 12:26:27 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkPolyDataNormalPlaneEstimator.h"

#include "vtkPolyDataConnectivityFilter.h"
#include "vtkFloatArray.h"
#include "vtkIdTypeArray.h"
#include "vtkIdList.h"
#include "vtkMath.h"
#include "vtkCell.h"
#include "vtkPointData.h"
#include "vtkPointLocator.h"
#include "vtkPolyData.h"
#include "vtkPolyDataNormals.h"

#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkVersion.h"


vtkStandardNewMacro(vtkvmtkPolyDataNormalPlaneEstimator);

vtkvmtkPolyDataNormalPlaneEstimator::vtkvmtkPolyDataNormalPlaneEstimator()
{
  this->UseConnectivity = 1;
  this->MinimumNeighborhoodSize = 10;
  this->OriginPointId = -1;
  this->Origin[0] = this->Origin[1] = this->Origin[2] = 0.0;
  this->Normal[0] = this->Normal[1] = this->Normal[2] = 0.0;
}

vtkvmtkPolyDataNormalPlaneEstimator::~vtkvmtkPolyDataNormalPlaneEstimator()
{
}

int vtkvmtkPolyDataNormalPlaneEstimator::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (this->OriginPointId == -1)
    {
    vtkErrorMacro("Origin point id not specified");
    return 1;
    }

  input->BuildCells();
  input->BuildLinks();

  vtkFloatArray* normals = vtkFloatArray::New();

  if (input->GetPointData()->GetNormals())
    {
      normals->DeepCopy(input->GetPointData()->GetNormals());
    }
  else
    {
      vtkPolyDataNormals* normalsFilter = vtkPolyDataNormals::New();
      normalsFilter->SetInputData(input);
      normalsFilter->AutoOrientNormalsOn();
      normalsFilter->FlipNormalsOn();
      normalsFilter->ConsistencyOn();
      normalsFilter->ComputeCellNormalsOff();
      normalsFilter->SplittingOff();
      normalsFilter->Update();

      normals->DeepCopy(normalsFilter->GetOutput()->GetPointData()->GetNormals());

      normalsFilter->Delete();
    }

  vtkPointLocator* locator = vtkPointLocator::New();
  locator->SetDataSet(input);
  locator->BuildLocator();

  vtkIdTypeArray* connectivityArray = vtkIdTypeArray::New();
  if (this->UseConnectivity)
  {
    vtkPolyDataConnectivityFilter* connectivityFilter = vtkPolyDataConnectivityFilter::New();
    connectivityFilter->SetInputData(input);
    connectivityFilter->SetExtractionModeToAllRegions();
    connectivityFilter->ColorRegionsOn();
    connectivityFilter->Update();

    connectivityArray->DeepCopy(connectivityFilter->GetOutput()->GetPointData()->GetScalars());
    connectivityFilter->Delete();
  }

  vtkIdType npts, *pts, *cells;
  unsigned short ncells;

  input->GetPointCells(this->OriginPointId,ncells,cells);

  double averageLength = 0.0;

  for (vtkIdType i=0; i<ncells; i++)
    {
      averageLength += sqrt(input->GetCell(cells[i])->GetLength2());
    }
  averageLength /= ncells;

  double radiusStep = averageLength;

  double direction[3];
  double normal0[3], normal1[3];

  input->GetPoint(this->OriginPointId,this->Origin);
  normals->GetTuple(this->OriginPointId,normal1);

  vtkIdType regionId = -1;
  if (this->UseConnectivity)
  {
    regionId = connectivityArray->GetValue(this->OriginPointId);
  }

  vtkIdList* pointIdsWithinRadius = vtkIdList::New();

  bool doneOnce = false;

  // Future improvement: only consider topologically connected vertices

  for (int k=0; k<100; k++) 
  {
    pointIdsWithinRadius->Initialize();

    double radius = k * radiusStep;
    locator->FindPointsWithinRadius(radius,this->Origin,pointIdsWithinRadius);

    vtkIdType numberOfIds = pointIdsWithinRadius->GetNumberOfIds();

    vtkIdType neighborhoodSize = numberOfIds;

    if (this->UseConnectivity)
    {
      for (vtkIdType i=0; i<numberOfIds; i++)
      {
        vtkIdType id = pointIdsWithinRadius->GetId(i);
        if (connectivityArray->GetValue(id) == regionId)
        {
          neighborhoodSize += 1;
        }
      }
    }

    if (neighborhoodSize < this->MinimumNeighborhoodSize)
    {
      continue;
    }

    double kdirection[3];
    kdirection[0] = kdirection[1] = kdirection[2] = 0.0;

    bool done = false;

    for (vtkIdType i=0; i<numberOfIds; i++) 
    {
      vtkIdType id = pointIdsWithinRadius->GetId(i);

      if (this->UseConnectivity && connectivityArray->GetValue(id) != regionId)
      {
        continue;
      }

      normals->GetTuple(id,normal0);

      double dot = vtkMath::Dot(normal0,normal1);

      if (fabs(dot) > 0.6) {
        continue;
      }

      if (dot < -0.5 && doneOnce) {
        done = true;
        break;
      }

      double cross[3];
      vtkMath::Cross(normal0,normal1,cross);

      if (vtkMath::Dot(kdirection,cross) < 0.0) {
        cross[0] *= -1.0;
        cross[1] *= -1.0;
        cross[2] *= -1.0;
      }

      kdirection[0] += cross[0];
      kdirection[1] += cross[1];
      kdirection[2] += cross[2];
      doneOnce = true;
    }

    if (!doneOnce)
    {
      continue;
    }

    vtkMath::Normalize(kdirection);

    if (done)
    {
      break;
    }

    this->Normal[0] = kdirection[0];
    this->Normal[1] = kdirection[1];
    this->Normal[2] = kdirection[2];
  }

  vtkMath::Normalize(this->Normal);

  normals->Delete();
  locator->Delete();
  pointIdsWithinRadius->Delete();
  connectivityArray->Delete();

  return 1;
}

void vtkvmtkPolyDataNormalPlaneEstimator::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


<|start_filename|>vtkVmtk/Contrib/vtkvmtkPolyDataDistanceToSpheres.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkPolyDataDistanceToSpheres.h,v $
  Language:  C++
  Date:      $$
  Version:   $$

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

  Note: this class was contributed by 
	<NAME>
	Kalkulo AS
	Simula Research Laboratory
=========================================================================*/
// .NAME vtkvmtkPolyDataDistanceToSpheres - ..
// .SECTION Description
// ..

#ifndef __vtkvmtkPolyDataDistanceToSpheres_h
#define __vtkvmtkPolyDataDistanceToSpheres_h

#include "vtkPolyDataAlgorithm.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"

#include "vtkPolyData.h"

class VTK_VMTK_CONTRIB_EXPORT vtkvmtkPolyDataDistanceToSpheres : public vtkPolyDataAlgorithm
{
public:
  static vtkvmtkPolyDataDistanceToSpheres* New();
  vtkTypeMacro(vtkvmtkPolyDataDistanceToSpheres,vtkPolyDataAlgorithm);

  vtkSetObjectMacro(Spheres,vtkPolyData);
  vtkGetObjectMacro(Spheres,vtkPolyData);

  vtkSetMacro(DistanceOffset,double);
  vtkGetMacro(DistanceOffset,double);
  
  vtkSetMacro(DistanceScale,double);
  vtkGetMacro(DistanceScale,double);
  
  vtkSetMacro(MinDistance,double);
  vtkGetMacro(MinDistance,double);
  
  vtkSetMacro(MaxDistance,double);
  vtkGetMacro(MaxDistance,double);

  vtkSetStringMacro(DistanceToSpheresArrayName);
  vtkGetStringMacro(DistanceToSpheresArrayName);

protected:
  vtkvmtkPolyDataDistanceToSpheres();
  ~vtkvmtkPolyDataDistanceToSpheres();

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  char* DistanceToSpheresArrayName;

  vtkPolyData* Spheres;

  double DistanceOffset;
  double DistanceScale;
  double MinDistance;
  double MaxDistance;


private:
  vtkvmtkPolyDataDistanceToSpheres(const vtkvmtkPolyDataDistanceToSpheres&);  // Not implemented.
  void operator=(const vtkvmtkPolyDataDistanceToSpheres&);  // Not implemented.
};

#endif



<|start_filename|>vtkVmtk/Misc/vtkvmtkStreamlineOsculatingCentersFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkStreamlineOsculatingCentersFilter.h,v $
Language:  C++
Date:      $Date: 2006/07/17 09:53:14 $
Version:   $Revision: 1.5 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkStreamlineOsculatingCentersFilter - Cluster streamlines based on Mahalanobis distance metric and K-Means clustering.
// .SECTION Description
// This class clusters streamlines.

#ifndef __vtkvmtkStreamlineOsculatingCentersFilter_h
#define __vtkvmtkStreamlineOsculatingCentersFilter_h

#include "vtkPolyDataAlgorithm.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_MISC_EXPORT vtkvmtkStreamlineOsculatingCentersFilter : public vtkPolyDataAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkStreamlineOsculatingCentersFilter,vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkStreamlineOsculatingCentersFilter *New();

  vtkSetObjectMacro(VoronoiDiagram,vtkPolyData);
  vtkGetObjectMacro(VoronoiDiagram,vtkPolyData);

  vtkSetStringMacro(VoronoiSheetIdsArrayName);
  vtkGetStringMacro(VoronoiSheetIdsArrayName);

  vtkGetObjectMacro(OsculatingCenters,vtkPolyData);

  protected:
  vtkvmtkStreamlineOsculatingCentersFilter();
  ~vtkvmtkStreamlineOsculatingCentersFilter();  

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  vtkPolyData* VoronoiDiagram;
  char* VoronoiSheetIdsArrayName;
  
  vtkPolyData* OsculatingCenters;

  private:
  vtkvmtkStreamlineOsculatingCentersFilter(const vtkvmtkStreamlineOsculatingCentersFilter&);  // Not implemented.
  void operator=(const vtkvmtkStreamlineOsculatingCentersFilter&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/Starbase.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*   ,d88""\   d8                    888                                     */
/*   8888    _d88__   o8888o  88o88o 888o888e    o8888o   d88"\  e88888e     */
/*   `Y88b    888         88b 888    888  888b       88b C88C   d888  88b    */
/*    `Y88b,  888    o888o888 888    888  8888  e888o888  "88b  8888oo888    */
/*      8888  888   C888  888 888    888  888P C888  888   `88D q888         */
/*   \_o88P'  "88o"  "888"888 888    888"888"   "888"888 \_88P   "88oooo"    */
/*                                                                           */
/*  A Tetrahedral Complex Data Structure Library.                            */
/*  (Starbase.c)                                                             */
/*                                                                           */
/*  Version 0.12                                                             */
/*  13 December 2008                                                         */
/*                                                                           */
/*  Portions of Starbase written prior to June 30, 1998 are                  */
/*  Copyright 1995, 1996, 1997, 1998                                         */
/*  <NAME>                                                */
/*  965 Sutter Street #815                                                   */
/*  San Francisco, California  94109-6082                                    */
/*  <EMAIL>                                                      */
/*                                                                           */
/*  Portions of Starbase written after June 30, 1998 are in the public       */
/*  domain, but Starbase as a whole is not.  All rights reserved.            */
/*                                                                           */
/*  This version of Starbase is provided as part of Stellar, a program for   */
/*  improving tetrahedral meshes.  Stellar and this version of Starbase are  */
/*  open source software provided under the Berkeley Source Distribution     */
/*  (BSD) license, which follows.  If you want to use Stellar in a           */
/*  commercial product, the BSD license permits you to do so freely.  Bryan  */
/*  Klingner and I request that you kindly send me an email to let us know   */
/*  what products include Stellar, but it is not a legal requirement.        */
/*                                                                           */
/*  ======================= BSD license begins here. ======================= */
/*                                                                           */
/*  Redistribution and use in source and binary forms, with or without       */
/*  modification, are permitted provided that the following conditions are   */
/*  met:                                                                     */
/*                                                                           */
/*  - Redistributions of source code must retain the above copyright notice, */
/*    this list of conditions and the following disclaimer.                  */
/*                                                                           */
/*  - Redistributions in binary form must reproduce the above copyright      */
/*    notice, this list of conditions and the following disclaimer in the    */
/*    documentation and/or other materials provided with the distribution.   */
/*                                                                           */
/*  - Neither the name of <NAME> nor the name of the University   */
/*    of California nor the names of its contributors may be used to endorse */
/*    or promote products derived from this software without specific prior  */
/*    written permission.                                                    */
/*                                                                           */
/*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS  */
/*  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED    */
/*  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A          */
/*  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT      */
/*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    */
/*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
/*  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR   */
/*  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF   */
/*  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     */
/*  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS       */
/*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.             */
/*                                                                           */
/*  ======================== BSD license ends here. ======================== */
/*                                                                           */
/*  Additional disclaimer:  Neither I nor any institution I have been        */
/*  associated with warrant this code in any way whatsoever.  This code is   */
/*  provided "as is".  Use at your own risk.                                 */
/*                                                                           */
/*  The triangulation data structures are adapted from the star-based        */
/*  simplex dictionary of <NAME>, <NAME>, <NAME>.     */
/*  Cardoze, and <NAME>, "Compact Representations of Simplicial       */
/*  Meshes in Two and Three Dimensions," International Journal of            */
/*  Computational Geometry and Applications 15(1):3-24, February 2005.       */
/*                                                                           */
/*  The algorithms for exact computation of the signs of determinants are    */
/*  described in <NAME>, "Adaptive Precision Floating-    */
/*  Point Arithmetic and Fast Robust Geometric Predicates," Discrete &       */
/*  Computational Geometry 18(3):305-363, October 1997.  (Also available as  */
/*  Technical Report CMU-CS-96-140, School of Computer Science, Carnegie     */
/*  Mellon University, Pittsburgh, Pennsylvania, May 1996.)                  */
/*  An abbreviated version appears as <NAME>, "Robust     */
/*  Adaptive Floating-Point Geometric Predicates," Proceedings of the        */
/*  Twelfth Annual Symposium on Computational Geometry, ACM, May 1996.       */
/*  Many of the ideas for my exact arithmetic routines originate with        */
/*  <NAME>, "Algorithms for Arbitrary Precision Floating Point    */
/*  Arithmetic," Tenth Symposium on Computer Arithmetic, pp. 132-143, IEEE   */
/*  Computer Society Press, 1991.  Many of the ideas for the correct         */
/*  evaluation of the signs of determinants are taken from <NAME>    */
/*  and <NAME>, "Efficient Exact Arithmetic for              */
/*  Computational Geometry," Proceedings of the Ninth Annual Symposium on    */
/*  Computational Geometry, ACM, pp. 163-172, May 1993, and from Steven      */
/*  Fortune, "Numerical Stability of Algorithms for 2D Delaunay Triangu-     */
/*  lations," International Journal of Computational Geometry & Applications */
/*  5(1-2):193-213, March-June 1995.                                         */
/*                                                                           */
/*  The geometric predicates appear in my "Lecture Notes on Geometric        */
/*  Robustness" at http://www.cs.berkeley.edu/~jrs/mesh .                    */
/*                                                                           */
/*  If you make any improvements to this code, please please please let me   */
/*  know, so that I may obtain the improvements.  Even if you don't change   */
/*  the code, I'd still love to hear what it's being used for.               */
/*                                                                           */
/*****************************************************************************/


/*  For single precision (which will save some memory and reduce paging),    */
/*  define the symbol SINGLE by using the -DSINGLE compiler switch or by     */
/*  writing "#define SINGLE" below.                                          */
/*                                                                           */
/*  For double precision (which will allow you to refine meshes to a smaller */
/*  edge length), leave SINGLE undefined.                                    */

/* #define SINGLE */

#ifdef SINGLE
typedef float starreal;
#else /* not SINGLE */
typedef double starreal;
#endif /* not SINGLE */

/*  To insert lots of self-checks for internal errors, define the SELF_CHECK */
/*  symbol.  This will slow down the program significantly.  It is best to   */
/*  define the symbol using the -DSELF_CHECK compiler switch, but you could  */
/*  write "#define SELF_CHECK" below.  If you are modifying this code, I     */
/*  recommend you turn self-checks on until your work is debugged.           */

/* #define SELF_CHECK */
/* #define PARANOID */

/*  On some machines, my exact arithmetic routines might be defeated by the  */
/*  use of internal extended precision floating-point registers.  The best   */
/*  way to solve this problem is to set the floating-point registers to use  */
/*  single or double precision internally.  On 80x86 processors, this may be */
/*  accomplished by setting the CPU86 symbol in Microsoft operating systems, */
/*  or the LINUX symbol in Linux.                                            */
/*                                                                           */
/*  An inferior solution is to declare certain values as `volatile', thus    */
/*  forcing them to be stored to memory and rounded off.  Unfortunately,     */
/*  this solution might slow Triangle down quite a bit.  To use volatile     */
/*  values, write "#define INEXACT volatile" below.  Normally, however,      */
/*  INEXACT should be defined to be nothing.  ("#define INEXACT".)           */
/*                                                                           */
/*  For more discussion, see Section 5 of my paper, "Adaptive Precision      */
/*  Floating-Point Arithmetic and Fast Robust Geometric Predicates" (also    */
/*  available as Section 6.6 of my dissertation).                            */

/* #define CPU86 */
/* #define LINUX */

#define INEXACT /* Nothing */
/* #define INEXACT volatile */

/*  Maximum number of characters in a file name (including the null).        */

#define FILENAMESIZE 2048

/*  Maximum number of characters in a line read from a file (including the   */
/*  null).                                                                   */

#define INPUTLINESIZE 1024

/*  A number that speaks for itself, every kissable digit.                   */

#define PI 3.141592653589793238462643383279502884197169399375105820974944592308


#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stddef.h>
#include <string.h>
#include <math.h>
#ifdef STARTIMER
#include <sys/time.h>
#endif /* not STARTIMER */
#ifdef CPU86
#include <float.h>
#endif /* CPU86 */
#ifdef LINUX
#include <fpu_control.h>
#endif /* LINUX */


/*  `starlong' and `starulong' are the types of integer (signed and          */
/*  unsigned, respectively) of most of the indices used internally and       */
/*  externally by Starbase, including vertex and tetrahedron numbers.  They  */
/*  determine the number of internal data structures that can be allocated,  */
/*  so long choices (e.g. ptrdiff_t and size_t, defined in stddef.h) are     */
/*  recommended.  If the number of tetrahedra might be around 2^28 or more,  */
/*  use 64-bit integers.  On a machine with 32-bit pointers (memory          */
/*  addresses), though, there's no point using integers bigger than 32 bits. */
/*  On a machine with limited memory, smaller integers might allow you to    */
/*  create larger meshes.                                                    */

typedef ptrdiff_t starlong;
typedef size_t starulong;


/*  Data structure for command line switches, file names, and operation      */
/*  counts.  Used (instead of global variables) to allow reentrancy.         */

struct behavior {

/*  Switches for the tetrahedralizer.                                        */
/*  Read the instructions to find out the meaning of these switches.         */

  int poly;                                                    /* -p switch. */
  int refine;                                                  /* -r switch. */
  int quality;                                                 /* -q switch. */
  /* Maximum acceptable tetrahedron circumradius-to-shortest edge ratio:     */
  starreal qmeasure;                           /* Specified after -q switch. */
  starreal minangle;          /* Min dehedral angle bound, after -q/ switch. */
  starreal goodangle;                         /* Cosine squared of minangle. */
  int varvolume;                      /* -a switch without number following. */
  int fixedvolume;                       /* -a switch with number following. */
  starreal maxvolume;    /* Maximum volume bound, specified after -a switch. */
  int usertest;                                                /* -u switch. */
  int regionattrib;                                            /* -A switch. */
  int convex;                                                  /* -c switch. */
  int weighted;                         /* 1 for -w switch, 2 for -W switch. */
  int conformdel;                                              /* -D switch. */
  int jettison;                                                /* -j switch. */
  int edgesout;                                                /* -e switch. */
  int facesout;                                                /* -f switch. */
  int voronoi;                                                 /* -v switch. */
  int neighbors;                                               /* -n switch. */
  int geomview;                                                /* -g switch. */
  int nobound;                                                 /* -B switch. */
  int nopolywritten;                                           /* -P switch. */
  int nonodewritten;                                           /* -N switch. */
  int noelewritten;                                            /* -E switch. */
  int noiterationnum;                                          /* -I switch. */
  int noholes;                                                 /* -O switch. */
  int noexact;                                                 /* -X switch. */
  /* All items are numbered starting from `firstnumber':                     */
  starulong firstnumber;                            /* Inverse of -z switch. */
  int order;                    /* Element order, specified after -o switch. */
  int nobisect;                 /* Count of how often -Y switch is selected. */
  starlong steiner;   /* Max # of Steiner points, specified after -S switch. */
  int jumpwalk;                                                /* -J switch. */
  int norandom;                                                /* -k switch. */
  int fullrandom;                                              /* -K switch. */
  int docheck;                                                 /* -C switch. */
  int quiet;                                                   /* -Q switch. */
  int verbose;                  /* Count of how often -V switch is selected. */
  /* Determines whether new vertices will be added, other than the input:    */
  int addvertices;                              /* -p, -q, -a, or -u switch. */
  /* Determines whether segments and facets are used at all:                 */
  int usefacets;                        /* -p, -r, -q, -a, -u, or -c switch. */

  int readnodefileflag;                       /* Has a .node file been read? */

/*  Variables for file names.                                                */

#ifndef STARLIBRARY
  char innodefilename[FILENAMESIZE];                    /* Input .node file. */
  char inelefilename[FILENAMESIZE];                      /* Input .ele file. */
  char inpolyfilename[FILENAMESIZE];                    /* Input .poly file. */
  char areafilename[FILENAMESIZE];                      /* Input .area file. */
  char outnodefilename[FILENAMESIZE];                  /* Output .node file. */
  char outelefilename[FILENAMESIZE];                    /* Output .ele file. */
  char outpolyfilename[FILENAMESIZE];                  /* Output .poly file. */
  char edgefilename[FILENAMESIZE];                     /* Output .edge file. */
  char facefilename[FILENAMESIZE];                     /* Output .face file. */
  char vnodefilename[FILENAMESIZE];                  /* Output .v.node file. */
  char vpolyfilename[FILENAMESIZE];                  /* Output .v.poly file. */
  char neighborfilename[FILENAMESIZE];                /* Output .neigh file. */
  char offfilename[FILENAMESIZE];                       /* Output .off file. */
#endif /* not STARLIBRARY */

/*  Counts of operations performed.                                          */

  starulong inspherecount;            /* Number of insphere tests performed. */
  starulong orientcount;        /* Number of 3D orientation tests performed. */
  starulong orient4dcount;      /* Number of 4D orientation tests performed. */
  starulong tetcircumcentercount;/* Number of tet circumcenter calculations. */
  starulong tricircumcentercount;    /* Triangular face circumcenter calc's. */

};                                              /* End of `struct behavior'. */

/*  Global constants.                                                        */

starreal splitter;   /* Used to split real factors for exact multiplication. */
starreal epsilon;                         /* Floating-point machine epsilon. */
starreal resulterrbound;
starreal o2derrboundA, o2derrboundB, o2derrboundC;
starreal o3derrboundA, o3derrboundB, o3derrboundC;
starreal isperrboundA, isperrboundB, isperrboundC;


/********* Memory allocation and program exit wrappers begin here    *********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  starexit()   Exits the program Starbase.                                 */
/*                                                                           */
/*  Used to give Starbase a single point of exit whose contents can easily   */
/*  be replaced to help interface with client programs.                      */
/*                                                                           */
/*  status:  Should be zero on normal termination; one if an error occurs.   */
/*                                                                           */
/*****************************************************************************/

void starexit(int status)
{
  exit(status);
}

/*****************************************************************************/
/*                                                                           */
/*  starmalloc()   Allocates memory from the operating system.               */
/*                                                                           */
/*  Used to give Starbase a single point of memory allocation whose contents */
/*  can easily be replaced to help interface with client programs.           */
/*                                                                           */
/*  size:  The number of contiguous bytes of memory to allocate.             */
/*                                                                           */
/*  Returns a pointer to the allocated memory.                               */
/*                                                                           */
/*****************************************************************************/

void *starmalloc(size_t size)
{
  void *memptr;

  memptr = malloc(size);
  if (memptr == (void *) NULL) {
    printf("Error:  Out of memory.\n");
    starexit(1);
  }
  return(memptr);
}

/*****************************************************************************/
/*                                                                           */
/*  starfree()   Returns previously allocated memory to the operating system.*/
/*                                                                           */
/*  Used to give Starbase a single point of memory freeing whose contents    */
/*  can easily be replaced to help interface with client programs.           */
/*                                                                           */
/*  memptr:  A pointer to the block of memory that should be freed so that   */
/*    it is available to be reallocated.                                     */
/*                                                                           */
/*****************************************************************************/

void starfree(void *memptr)
{
  free(memptr);
}

/**                                                                         **/
/**                                                                         **/
/********* Memory allocation and program exit wrappers end here      *********/


/********* User interaction routines begin here                      *********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  internalerror()   Ask the user to send me the defective product.  Exit.  */
/*                                                                           */
/*****************************************************************************/

void internalerror(void)
{
  printf("  Please report this bug to <EMAIL>\n");
  printf("  Include the message above, your input data set, and the exact\n");
  printf("  command line you used to run Star.\n");
  starexit(1);
}

/*****************************************************************************/
/*                                                                           */
/*  syntax()   Print a list of command line switches.                        */
/*                                                                           */
/*****************************************************************************/

#ifndef STARLIBRARY

void syntax(void)
{
#ifdef CDT_ONLY
  printf("Star [-pAcwWjefvngBPNEIOXzo_CQVh] input_file\n");
#else /* not CDT_ONLY */
  printf("Star [-prq__a__uAcwWDjefvngBPNEIOXzo_YSkK__CQVh] input_file\n");
#endif /* not CDT_ONLY */

  printf("    -p  Tetrahedralizes a polyhedron or PLC (.poly file).\n");
#ifndef CDT_ONLY
  printf("    -r  Refines a previously generated mesh.\n");
  printf("    -q  Quality mesh generation.\n");
  printf("    -a  Applies a maximum tetrahedron volume constraint.\n");
  printf("    -u  Applies a user-defined tetrahedron constraint.\n");
#endif /* not CDT_ONLY */
  printf("    -A  Applies attributes to identify tetrahedra in certain "
         "regions.\n");
  printf("    -c  Encloses the convex hull with facets.\n");
  printf("    -w  Weighted Delaunay triangulation.\n");
  printf("    -W  Regular triangulation (lower convex hull of a height "
         "field).\n");
#ifndef CDT_ONLY
  printf("    -D  Conforming Delaunay:  attempts to make tetrahedra "
         "Delaunay.\n");
#endif /* not CDT_ONLY */
  printf("    -j  Renumber nodes and jettison unused vertices from output.\n");
  printf("    -e  Generates an edge list (.edge file).\n");
  printf("    -f  Generates a face list (.face file).\n");
  printf("    -v  Generates a Voronoi diagram.\n");
  printf("    -n  Generates a list of tetrahedron neighbors (.neigh file).\n");
  printf("    -g  Generates an .off file for Geomview.\n");
  printf("    -B  Suppresses output of boundary information.\n");
  printf("    -P  Suppresses output of .poly file.\n");
  printf("    -N  Suppresses output of .node file.\n");
  printf("    -E  Suppresses output of .ele file.\n");
  printf("    -I  Suppresses mesh iteration numbers.\n");
  printf("    -O  Ignores holes in .poly file.\n");
  printf("    -X  Suppresses use of exact arithmetic.\n");
  printf("    -z  Numbers all items starting from zero (rather than one).\n");
  printf("    -o2 Generates second-order subparametric elements.\n");
#ifndef CDT_ONLY
  printf("    -Y  Suppresses boundary facet splitting.\n");
  printf("    -S  Specifies maximum number of added Steiner points.\n");
#endif /* not CDT_ONLY */
  printf("    -k  Insert vertices in original order (no randomization).\n");
  printf("    -K  Insert vertices in fully random order (instead of BRIO).\n");
  printf("    -C  Check consistency of final mesh.\n");
  printf("    -Q  Quiet:  No terminal output except errors.\n");
  printf("    -V  Verbose:  Detailed information on what I'm doing.\n");
  printf("    -h  Help:  Detailed instructions for Star.\n");
  printf("PRE-RELEASE CODE:  DO NOT DISTRIBUTE!!!\n");
  printf("EXPECT THIS CODE TO BE BUGGY AND SLOW.\n");
  starexit(0);
}

/* bryan's one-off syntax */
void stellarsyntax(void)
{
  printf("Usage:\n\n");
  printf("Stellar [-s configfile -L verbosity -F] input_file\n");

  printf("    -s  The filename that follows will set all of Stellar's options.\n"); 
  printf("        (This is the primary method for controlling Stellar's behavior.\n");
  printf("        refer to EXAMPLE_CONFIG for a description of configuration options.)\n");
  printf("    -L  The integer >= 0 that follows will set the verbosity of Stellar's output.\n");
  printf("    -F  Compute quality statistics of the input mesh, output them and quit.\n");
  starexit(0);
}

#endif /* not STARLIBRARY */

/*****************************************************************************/
/*                                                                           */
/*  info()   Print out complete instructions.                                */
/*                                                                           */
/*****************************************************************************/

#ifndef STARLIBRARY

void info(void)
{
  printf("Star\n");
  printf(
"A Three-Dimensional Quality Mesh Generator and Delaunay Tetrahedralizer.\n");
  printf("Version 0.1\n\n");
  printf("Copyright 1995, 1996, 1997, 1998 <NAME>\n");
  printf("2360 Woolsey #H / Berkeley, California  94705-1927\n");
  printf("Bugs/comments to <EMAIL>\n");
  printf(
"Created as part of the Quake project (tools for earthquake simulation).\n");
  printf(
"Supported in part by NSF Award CMS-9318163 and an NSERC 1967 Scholarship.\n");
  printf("There is no warranty whatsoever.  Use at your own risk.\n");
  printf("PRE-RELEASE CODE:  DO NOT DISTRIBUTE!!!\n");
  printf("EXPECT THIS CODE TO BE BUGGY.\n");
#ifdef SINGLE
  printf("This executable is compiled for single precision arithmetic.\n\n\n");
#else /* not SINGLE */
  printf("This executable is compiled for double precision arithmetic.\n\n\n");
#endif /* not SINGLE */
  starexit(0);
}

/* bryan's short, one-off info function */
void stellarinfo(void)
{
  printf("Stellar\n");
  printf(
"A Tetrahedral Mesh Improvement Program.\n");
  printf("Version 0.1\n\n");
  printf("Copyright 2006-2008 <NAME>\n");
  printf("Bugs/comments to <EMAIL>\n");
#ifdef SINGLE
  printf("This executable is compiled for single precision arithmetic.\n\n\n");
#else /* not SINGLE */
  printf("This executable is compiled for double precision arithmetic.\n\n\n");
#endif /* not SINGLE */
  starexit(0);
}

#endif /* not STARLIBRARY */

/*****************************************************************************/
/*                                                                           */
/*  parsecommandline()   Read the command line, identify switches, and set   */
/*                       up options and file names.                          */
/*                                                                           */
/*  argc:  The number of strings on the command line.                        */
/*  argv:  An array of the strings on the command line.                      */
/*  b:  The struct storing Star's options and file names.                    */
/*                                                                           */
/*****************************************************************************/

void parsecommandline(int argc, char **argv, struct behavior *b)
{
#ifdef STARLIBRARY
#define STARTINDEX 0
#else /* not STARLIBRARY */
#define STARTINDEX 1
  int increment;
  int meshnumber;
#endif /* not STARLIBRARY */
  int i, j, k;
  char workstring[FILENAMESIZE];

  /* See the comments above the definition of `struct behavior' for the */
  /*   meaning of most of these variables.                              */
  b->inspherecount = 0;
  b->orientcount = 0;
  b->orient4dcount = 0;
  b->tetcircumcentercount = 0;
  b->tricircumcentercount = 0;

  b->poly = b->refine = b->quality = 0;
  b->varvolume = b->fixedvolume = b->usertest = 0;
  b->regionattrib = b->convex = b->weighted = b->jettison = 0;
  b->firstnumber = 1;
  b->edgesout = b->facesout = b->voronoi = b->neighbors = b->geomview = 0;
  b->nobound = b->nopolywritten = b->nonodewritten = b->noelewritten = 0;
  b->noiterationnum = 0;
  b->noholes = b->noexact = 0;
  b->docheck = 0;
  b->nobisect = 0;
  b->conformdel = 0;
  /* A negative `steiner' value indicates no constraint on number of */
  /*   Steiner points.                                               */
  b->steiner = -1;
  b->order = 1;
  b->qmeasure = 0.0;
  b->minangle = 0.0;
  /* A negative volume indicates no constraint on tetrahedron volumes. */
  b->maxvolume = -1.0;
  b->quiet = b->verbose = 0;
#ifndef STARLIBRARY
  b->innodefilename[0] = '\0';
#endif /* not STARLIBRARY */

  for (i = STARTINDEX; i < argc; i++) {
#ifndef STARLIBRARY
    if (argv[i][0] == '-') {
#endif /* not STARLIBRARY */
      for (j = STARTINDEX; argv[i][j] != '\0'; j++) {
        if (argv[i][j] == 'p') {
          b->poly = 1;
	}
#ifndef CDT_ONLY
        if (argv[i][j] == 'r') {
          b->refine = 1;
	}
        if (argv[i][j] == 'q') {
          b->quality = 1;
          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
              (argv[i][j + 1] == '.')) {
            /* Read a numerical bound on the largest permissible */
            /*   circumradius-to-shortest edge ratio.            */
            k = 0;
            while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                   (argv[i][j + 1] == '.')) {
              j++;
              workstring[k] = argv[i][j];
              k++;
            }
            workstring[k] = '\0';
            b->qmeasure = (starreal) strtod(workstring, (char **) NULL);
          } else {
            /* Largest permissible circumradius-to-shortest edge ratio is 2. */
            b->qmeasure = 2.0;
          }
          if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
            j++;
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              /* Read a numerical bound on the smallest permissible */
              /*   dihedral angle.                                  */
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              b->minangle = (starreal) strtod(workstring, (char **) NULL);
            } else {
              /* Smallest permissible dihedral angle is 5 degrees. */
              b->minangle = 5.0;
            }
          }
        }
        if (argv[i][j] == 'a') {
          b->quality = 1;
          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
              (argv[i][j + 1] == '.')) {
            b->fixedvolume = 1;
            /* Read a numerical bound on the largest permissible */
            /*   tetrahedron volume.                             */
            k = 0;
            while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                   (argv[i][j + 1] == '.')) {
              j++;
              workstring[k] = argv[i][j];
              k++;
            }
            workstring[k] = '\0';
            b->maxvolume = (starreal) strtod(workstring, (char **) NULL);
            if (b->maxvolume <= 0.0) {
              printf("Error:  Maximum volume must be greater than zero.\n");
              starexit(1);
	    }
	  } else {
            b->varvolume = 1;
	  }
	}
        if (argv[i][j] == 'u') {
          b->quality = 1;
          b->usertest = 1;
        }
#endif /* not CDT_ONLY */
        if (argv[i][j] == 'A') {
          b->regionattrib = 1;
        }
        if (argv[i][j] == 'c') {
          b->convex = 1;
        }
        if (argv[i][j] == 'w') {
          b->weighted = 1;
        }
        if (argv[i][j] == 'W') {
          b->weighted = 2;
        }
        if (argv[i][j] == 'j') {
          b->jettison = 1;
        }
        if (argv[i][j] == 'z') {
          b->firstnumber = 0;
        }
        if (argv[i][j] == 'e') {
          b->edgesout = 1;
	}
        if (argv[i][j] == 'f') {
          b->facesout = 1;
	}
        if (argv[i][j] == 'v') {
          b->voronoi = 1;
	}
        if (argv[i][j] == 'n') {
          b->neighbors = 1;
	}
        if (argv[i][j] == 'g') {
          b->geomview = 1;
	}
        if (argv[i][j] == 'B') {
          b->nobound = 1;
	}
        if (argv[i][j] == 'P') {
          b->nopolywritten = 1;
	}
        if (argv[i][j] == 'N') {
          b->nonodewritten = 1;
	}
        if (argv[i][j] == 'E') {
          b->noelewritten = 1;
	}
#ifndef STARLIBRARY
        if (argv[i][j] == 'I') {
          b->noiterationnum = 1;
	}
#endif /* not STARLIBRARY */
        if (argv[i][j] == 'O') {
          b->noholes = 1;
	}
        if (argv[i][j] == 'X') {
          b->noexact = 1;
	}
        if (argv[i][j] == 'o') {
          if (argv[i][j + 1] == '2') {
            j++;
            b->order = 2;
          }
	}
#ifndef CDT_ONLY
        if (argv[i][j] == 'Y') {
          b->nobisect++;
	}
        if (argv[i][j] == 'S') {
          b->steiner = 0;
          /* Read a numerical bound on the maximum number of Steiner points. */
          while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
            j++;
            b->steiner = b->steiner * 10l + (starlong) (argv[i][j] - '0');
          }
        }
        if (argv[i][j] == 'D') {
          b->conformdel = 1;
        }
#endif /* not CDT_ONLY */
        if (argv[i][j] == 'k') {
          b->norandom = 1;
        }
        if (argv[i][j] == 'K') {
          b->fullrandom = 1;
        }
        if (argv[i][j] == 'C') {
          b->docheck = 1;
        }
        if (argv[i][j] == 'Q') {
          b->quiet = 1;
        }
        if (argv[i][j] == 'V') {
          b->verbose++;
        }
#ifndef STARLIBRARY
        if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
            (argv[i][j] == '?')) {
          stellarinfo();
	}
#endif /* not STARLIBRARY */
      }
#ifndef STARLIBRARY
    } else {
      /* Any command-line parameter not starting with "-" is assumed to be */
      /*   a file name.                                                    */
      strncpy(b->innodefilename, argv[i], FILENAMESIZE - 1);
      b->innodefilename[FILENAMESIZE - 1] = '\0';
    }
#endif /* not STARLIBRARY */
  }

#ifndef STARLIBRARY
  if (b->innodefilename[0] == '\0') {
    /* No file name specified; print a summary of the command line switches. */
    stellarsyntax();
  }

  /* Remove the filename extension (if any) and use it to infer switches */
  /*   that might not have been specified directly.                      */
  if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 5], ".node")) {
    b->innodefilename[strlen(b->innodefilename) - 5] = '\0';
  }
  if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 5], ".poly")) {
    b->innodefilename[strlen(b->innodefilename) - 5] = '\0';
    b->poly = 1;
  }
#ifndef CDT_ONLY
  if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 4], ".ele")) {
    b->innodefilename[strlen(b->innodefilename) - 4] = '\0';
    b->refine = 1;
  }
  if (!strcmp(&b->innodefilename[strlen(b->innodefilename) - 5], ".area")) {
    b->innodefilename[strlen(b->innodefilename) - 5] = '\0';
    b->refine = 1;
    b->quality = 1;
    b->varvolume = 1;
  }
#endif /* not CDT_ONLY */
#endif /* not STARLIBRARY */

  b->addvertices = b->poly || b->quality;
  b->usefacets = b->poly || b->refine || b->quality || b->convex;
  /* Compute the square of the cosine of the dihedral angle bound. */
  b->goodangle = cos(b->minangle * PI / 180.0);
  b->goodangle *= b->goodangle;
  if (b->refine && b->noiterationnum) {
    printf(
      "Error:  You cannot use the -I switch when refining a triangulation.\n");
    starexit(1);
  }
  /* Be careful not to allocate space for element volume constraints that */
  /*   will never be assigned any value (other than the default -1.0).    */
  if (!b->refine && !b->poly) {
    b->varvolume = 0;
  }
  /* Be careful not to add an extra attribute to each element unless the */
  /*   input supports it (PLC in, but not refining a preexisting mesh).  */
  if (b->refine || !b->poly) {
    b->regionattrib = 0;
  }
  /* Regular/weighted triangulations are incompatible with PLCs and meshing. */
  if (b->weighted && (b->poly || b->quality)) {
    b->weighted = 0;
    if (!b->quiet) {
      printf("Warning:  weighted triangulations (-w, -W) are incompatible\n");
      printf("  with PLCs (-p) and meshing (-q, -a, -u).  Weights ignored.\n");
    }
  }
  if (b->jettison && b->noiterationnum && !b->poly && !b->quiet) {
    printf("Warning:  -j and -I switches are largely incompatible.\n");
    printf("  The vertices are renumbered, so you will need the output\n");
    printf("  .node file to determine the new node indices.");
  } else if (b->jettison && b->nonodewritten && !b->quiet) {
    printf("Warning:  -j and -N switches are somewhat incompatible.\n");
    printf("  The vertices are renumbered, so you will need the output\n");
    printf("  .node file to determine the new node indices.");
  }

#ifndef STARLIBRARY
  strcpy(b->inpolyfilename, b->innodefilename);
  strcpy(b->inelefilename, b->innodefilename);
  strcpy(b->areafilename, b->innodefilename);
  /* Check the input filename for an iteration number. */
  increment = 0;
  strcpy(workstring, b->innodefilename);
  /* Find the last period in the filename. */
  j = 1;
  while (workstring[j] != '\0') {
    if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
      increment = j + 1;
    }
    j++;
  }
  /* The iteration number is zero by default, unless there's an iteration */
  /*   number in the filename.                                            */
  meshnumber = 0;
  if (increment > 0) {
    /* Read the iteration number from the end of the filename. */
    j = increment;
    do {
      if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
        meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
      } else {
        /* Oops, not a digit; this isn't an iteration number after all. */
        increment = 0;
        meshnumber = 0;
        break;
      }
      j++;
    } while (workstring[j] != '\0');
  }
  if (b->noiterationnum) {
    /* Do not use iteration numbers. */
    strcpy(b->outnodefilename, b->innodefilename);
    strcpy(b->outelefilename, b->innodefilename);
    strcpy(b->edgefilename, b->innodefilename);
    strcpy(b->facefilename, b->innodefilename);
    strcpy(b->vnodefilename, b->innodefilename);
    strcpy(b->vpolyfilename, b->innodefilename);
    strcpy(b->neighborfilename, b->innodefilename);
    strcpy(b->offfilename, b->innodefilename);
    strcat(b->outnodefilename, ".node");
    strcat(b->outelefilename, ".ele");
    strcat(b->edgefilename, ".edge");
    strcat(b->facefilename, ".face");
    strcat(b->vnodefilename, ".v.node");
    strcat(b->vpolyfilename, ".v.poly");
    strcat(b->neighborfilename, ".neigh");
    strcat(b->offfilename, ".off");
  } else if (increment == 0) {
    /* Input iteration number is zero; output iteration number is one. */
    strcpy(b->outnodefilename, b->innodefilename);
    strcpy(b->outpolyfilename, b->innodefilename);
    strcpy(b->outelefilename, b->innodefilename);
    strcpy(b->edgefilename, b->innodefilename);
    strcpy(b->facefilename, b->innodefilename);
    strcpy(b->vnodefilename, b->innodefilename);
    strcpy(b->vpolyfilename, b->innodefilename);
    strcpy(b->neighborfilename, b->innodefilename);
    strcpy(b->offfilename, b->innodefilename);
    strcat(b->outnodefilename, ".1.node");
    strcat(b->outpolyfilename, ".1.poly");
    strcat(b->outelefilename, ".1.ele");
    strcat(b->edgefilename, ".1.edge");
    strcat(b->facefilename, ".1.face");
    strcat(b->vnodefilename, ".1.v.node");
    strcat(b->vpolyfilename, ".1.v.poly");
    strcat(b->neighborfilename, ".1.neigh");
    strcat(b->offfilename, ".1.off");
  } else {
    /* Higher iteration numbers. */
    workstring[increment] = '%';
    workstring[increment + 1] = 'd';
    workstring[increment + 2] = '\0';
    sprintf(b->outnodefilename, workstring, meshnumber + 1);
    strcpy(b->outpolyfilename, b->outnodefilename);
    strcpy(b->outelefilename, b->outnodefilename);
    strcpy(b->edgefilename, b->outnodefilename);
    strcpy(b->facefilename, b->outnodefilename);
    strcpy(b->vnodefilename, b->outnodefilename);
    strcpy(b->vpolyfilename, b->outnodefilename);
    strcpy(b->neighborfilename, b->outnodefilename);
    strcpy(b->offfilename, b->outnodefilename);
    strcat(b->outnodefilename, ".node");
    strcat(b->outpolyfilename, ".poly");
    strcat(b->outelefilename, ".ele");
    strcat(b->edgefilename, ".edge");
    strcat(b->facefilename, ".face");
    strcat(b->vnodefilename, ".v.node");
    strcat(b->vpolyfilename, ".v.poly");
    strcat(b->neighborfilename, ".neigh");
    strcat(b->offfilename, ".off");
  }
  strcat(b->innodefilename, ".node");
  strcat(b->inpolyfilename, ".poly");
  strcat(b->inelefilename, ".ele");
  strcat(b->areafilename, ".area");
#endif /* not STARLIBRARY */
}

/**                                                                         **/
/**                                                                         **/
/********* User interaction routines end here                        *********/


/********* Miscellaneous routines begin here                         *********/
/**                                                                         **/
/**                                                                         **/

/* Random number seed is not constant, but I've made it global anyway.       */
/*   This should not hurt reentrancy (unless you want repeatability).        */

unsigned long randomseed = 1;                 /* Current random number seed. */

/*****************************************************************************/
/*                                                                           */
/*  randomnation()   Generate a random number between 0 and `choices' - 1.   */
/*                                                                           */
/*  This is a simple linear congruential random number generator.  Hence, it */
/*  is a bad random number generator, but good enough for most randomized    */
/*  geometric algorithms.                                                    */
/*                                                                           */
/*****************************************************************************/

unsigned long randomnation(unsigned long choices)
{
  unsigned long newrandom;

  if (choices >= 714025lu) {
    newrandom = (randomseed * 1366lu + 150889lu) % 714025lu;
    randomseed = (newrandom * 1366lu + 150889lu) % 714025lu;
    newrandom = newrandom * (choices / 714025lu) + randomseed;
    if (newrandom >= choices) {
      return newrandom - choices;
    } else {
      return newrandom;
    }
  } else {
    randomseed = (randomseed * 1366lu + 150889lu) % 714025lu;
    return randomseed % choices;
  }
}

/**                                                                         **/
/**                                                                         **/
/********* Miscellaneous routines end here                           *********/


/********* Tiered array memory pool routines begin here              *********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  Tiered arrays, which double as memory pools (struct arraypool)           */
/*                                                                           */
/*  Resizable arrays are a lovely data structure, because they allow you to  */
/*  access objects quickly by number, without limiting how many objects you  */
/*  can allocate.  Unfortunately, the usual technique for resizing arrays is */
/*  to copy everything from the old array to the new, then discard the old.  */
/*  It is not usually possible to reuse the old array's space for the new    */
/*  array.  For an application that uses the computer's entire main memory,  */
/*  this is not acceptable.                                                  */
/*                                                                           */
/*  Hence, tiered arrays, which seem to be part of the oral tradition of     */
/*  computer science, but are rarely covered in data structures textbooks.   */
/*  The simplest kind of tiered array, used here, has two tiers.  The upper  */
/*  tier is a single long array of pointers to second-tier blocks.  The      */
/*  second tier is composed of blocks, each containing the same fixed number */
/*  of objects.                                                              */
/*                                                                           */
/*  Each (nonnegative) array index addresses a particular object in a        */
/*  particular second-tier block.  The most significant bits of the index    */
/*  choose a second-tier block by addressing a pointer in the top tier       */
/*  array.  The remaining, less significant bits address an object within    */
/*  the block.  A tiered array is slightly slower than a normal array,       */
/*  because it requires an extra indiretion; but the top tier is small       */
/*  enough to cache well, so this is rarely a big handicap.                  */
/*                                                                           */
/*  Second-tier blocks are allocated one at a time, as necessary.  The       */
/*  top-tier array is resized in the usual manner.  However, the top tier    */
/*  comprises such a small percentage of the tiered array's total memory,    */
/*  it doesn't matter much if the old, discarded upper tier's memory is not  */
/*  reused.                                                                  */
/*                                                                           */
/*  The tiered array implemented here can be used in two different ways:  as */
/*  a normal array, or as a memory allocator (for objects of a single size)  */
/*  that can allocate and free objects, managing the index space itself.     */
/*  It's not usually wise to mix these two modes, though it can be done.     */
/*                                                                           */
/*  For a normal array, use the procedure arraypoolforcelookup(), which      */
/*  makes sure that an object with the given index exists, then returns a    */
/*  pointer to it.  For this behavior, initialize the arraypool by passing   */
/*  an `alloctype' of 0 to arraypoolinit().  Once an object has been         */
/*  initialized, it can be accessed quickly with the arraypoolfastlookup()   */
/*  macro, which is much faster than arraypoolforcelookup().                 */
/*                                                                           */
/*  For a memory allocator, either use arraypoolnewindex() and               */
/*  arraypoolfreeindex(), which allocate and free array indices, or          */
/*  arraypoolnewptr() and arraypoolfreeptr(), which allocate and free        */
/*  pointers.  For the former behavior, pass an `alloctype' of 1 to          */
/*  arraypoolinit().  For the latter behavior, pass an `alloctype' of 2.     */
/*                                                                           */
/*  Public interface:                                                        */
/*  typedef arraypoolulong   Unsigned array index.                           */
/*  struct arraypool   Tiered array (and memory pool) object.                */
/*  void arraypoolinit(pool, objectbytes, log2objectsperblock, alloctype)    */
/*    Initialize an arraypool for allocation of objects.                     */
/*  void arraypoolrestart(pool)   Deallocate all objects (but not to OS).    */
/*  void arraypooldeinit(pool)   Free an arraypool's memory to the OS.       */
/*  void *arraypoolforcelookup(pool, index)   Dereference; create if absent. */
/*  void *arraypoollookup(pool, index)   Dereference; return NULL if absent. */
/*  void *arraypoolfastlookup(pool, index)   Unsafe dereference; fast macro. */
/*  arraypoolulong arraypoolnewindex(pool, newptr)   Allocate object,        */
/*    returning an array index.                                              */
/*  void *arraypoolnewptr(pool)   Allocate object, returning a pointer.      */
/*  arraypoolulong arraypoolallocated(pool)   Return maximum number of       */
/*    objects allocated.                                                     */
/*  arraypoolulong arraypoolbytes(pool)   Return bytes of dynamic memory     */
/*    used by the tiered array.                                              */
/*  With `alloctype' 1 only:                                                 */
/*  void arraypoolfreeindex(pool, dyingindex)   Deallocate index for reuse.  */
/*  With `alloctype' 2 only:                                                 */
/*  void arraypoolfreeptr(pool, dyingobject)   Deallocate pointer for reuse. */
/*                                                                           */
/*  For internal use only:                                                   */
/*  char *arraypoolsecondtier(pool, index)                                   */
/*                                                                           */
/*****************************************************************************/

/*  `arraypoolulong' is the type of (unsigned) int used by the tiered array  */
/*  memory pool.  It determines the number of objects that can be allocated  */
/*  and the size of the array indices that may be used, so a long choice     */
/*  (e.g. size_t, defined in stddef.h) is recommended.  However, choosing a  */
/*  shorter type may make the tiered array occupy less memory in the case    */
/*  where arraypoolinit() is called with alloctype == 1, which forces each   */
/*  object to occupy at least as much space as an `arraypoolulong'.          */

typedef starulong arraypoolulong;


/*  TOPARRAYSTARTSIZE is the initial size of the top tier of the tiered      */
/*  array, namely the array `toparray'.  Its value is not critical, as the   */
/*  `toparray' is enlarged whenever necessary.                               */

#define TOPARRAYSTARTSIZE 128

/*  When the `toparray' runs out of room, it is enlarged, its length         */
/*  multiplied by the following factor.  If you think that the freed space   */
/*  occupied by the old array will not be reused (e.g. it's too small to be  */
/*  re-malloc'd for any other purpose), then a factor of 3 minimizes the     */
/*  average-case memory wasted.  If you think the freed space will be        */
/*  reused, then a factor of (1 + epsilon) minimizes the average-case memory */
/*  wasted, but you should choose at least 2 for speed's sake.               */

#define TOPRESIZEFACTOR 3

/*  NOTAPOOLINDEX is an index denoting no freed object in the arraypool.     */

#define NOTAPOOLINDEX ((arraypoolulong) ~0)


/*  An arraypool is a two-tiered array from which object can be allocated,   */
/*  either by index or by pointer.  `toparray' is a pointer to the upper     */
/*  tier, which is an array of pointers to the blocks that make up the lower */
/*  tier; and `toparraylen' is the upper tier's length.                      */
/*                                                                           */
/*  There are two mutually exclusive ways to store the stack of freed        */
/*  objects that are waiting to be reallocated.  `deadindexstack' and        */
/*  `deadobjectstack' store the indices or pointers, respectively, of the    */
/*  freed objects.  Indices are more flexible, as they can be converted to   */
/*  pointers, whereas pointers cannot be converted to indices.               */
/*                                                                           */
/*  Other fields are explained by comments below.  `objectsperblock' must be */
/*  2 raised to an integral power.  `objects' is a count of objects that the */
/*  arraypool has allocated for the client, NOT a count of objects malloc'd  */
/*  from the operating system.  `objects' does not include objects that have */
/*  been freed and are waiting on the dead stack to be reallocated.          */
/*  `objects' does not include objects that a client has accessed directly   */
/*  by a call to arraypoolforcelookup() without first being allocated by the */
/*  arraypool.                                                               */

struct arraypool {
  arraypoolulong objectbytes;       /* Size of one object in the lower tier. */
  arraypoolulong objectsperblock;           /* Objects per lower tier block. */
  arraypoolulong log2objectsperblock;      /* Base-2 logarithm of the above. */
  arraypoolulong totalmemory;     /* Total bytes used by whole tiered array. */
  arraypoolulong objects;          /* Number of currently allocated objects. */

  char **toparray;                             /* Pointer to the upper tier. */
  arraypoolulong toparraylen;      /* Length of the upper tier, in pointers. */
  arraypoolulong firstvirgin;          /* First never-allocated array index. */
  arraypoolulong deadindexstack;        /* Stack of freed objects, by index. */
  void *deadobjectstack;              /* Stack of freed objects, by pointer. */
};


/*****************************************************************************/
/*                                                                           */
/*  arraypoolrestart()   Deallocate all objects in an arraypool.             */
/*                                                                           */
/*  The arraypool returns to a fresh state, like after it was initialized    */
/*  by poolinit(), except that no memory is freed to the operating system.   */
/*  Rather, the previously allocated blocks are ready to be reused.          */
/*                                                                           */
/*  pool:  The arraypool to restart.                                         */
/*                                                                           */
/*****************************************************************************/

void arraypoolrestart(struct arraypool *pool)
{
  /* No objects have been freed. */
  pool->deadobjectstack = (void *) NULL;
  pool->deadindexstack = NOTAPOOLINDEX;
  /* Every object is ready to allocate. */
  pool->firstvirgin = 0;
  pool->objects = 0;
}

/*****************************************************************************/
/*                                                                           */
/*  arraypoolinit()   Initialize an arraypool for allocation of objects.     */
/*                                                                           */
/*  Before an arraypool may be used, it must be initialized by this          */
/*  procedure.  After initialization, memory can be allocated and freed in   */
/*  an arraypool, and array indices can be "dereferenced", by use of the     */
/*  other procedures.  arraypoolinit() does not allocate any memory from the */
/*  operating system itself.                                                 */
/*                                                                           */
/*  Don't call this procedure on an arraypool that has already been          */
/*  initialized (by this procedure), unless you call arraypooldeinit() on    */
/*  it first.  You will leak memory.  Also see arraypoolrestart().           */
/*                                                                           */
/*  pool:  The arraypool to initialize.                                      */
/*  objectbytes:  The number of bytes in each object.                        */
/*  log2objectsperblock:  The base-2 logarithm of the number of objects in   */
/*    each block of the second tier.  (The latter number must be 2 raised to */
/*    an integral power, and this interface ensures that.)                   */
/*  alloctype:  Sets the method used to maintain freed objects, as follows.  */
/*    0:  The arraypool does not manage freeing of objects at all.  Objects  */
/*        can be allocated, using arraypoolnewindex() or arraypoolnewptr(),  */
/*        or accessed (and allocated) directly by supplying an index to      */
/*        arraypoolforcelookup() (in which case the client must manage its   */
/*        own index space, and `objects' is not a correct count).  The       */
/*        advantage of disallowing freeing is that objects can be as short   */
/*        as one byte.                                                       */
/*    1:  The arraypool manages indices for the client via                   */
/*        arraypoolnewindex() and arraypoolfreeindex().  However, each       */
/*        object is made long enough to accommodate an arraypoolulong, if it */
/*        isn't already.  (To accommodate the stack of dead objects.)        */
/*    2:  The arraypool manages pointers for the client via                  */
/*        arraypoolnewptr() and arraypoolfreeptr().  If indices are not      */
/*        needed, this is convenient because it skips the index-to-pointer   */
/*        "dereferencing" step.  Each object is made long enough to          */
/*        accommodate a pointer.                                             */
/*                                                                           */
/*****************************************************************************/

void arraypoolinit(struct arraypool *pool,
                   arraypoolulong objectbytes,
                   arraypoolulong log2objectsperblock,
                   int alloctype)
{
  if (alloctype == 0) {
    /* Each object must be at least one byte long. */
    pool->objectbytes = objectbytes > 1 ? objectbytes : 1;
  } else if (alloctype == 1) {
    /* Each object must be at least sizeof(arraypoolulong) bytes long. */
    pool->objectbytes = objectbytes > sizeof(arraypoolulong) ?
                        objectbytes : sizeof(arraypoolulong);
  } else {
    /* Each object must be at least as long as a pointer. */
    pool->objectbytes = objectbytes > sizeof(void *) ?
                        objectbytes : sizeof(void *);
  }

  pool->log2objectsperblock = log2objectsperblock;
  /* Compute the number of objects in each block of the second tier. */
  pool->objectsperblock = ((arraypoolulong) 1) << pool->log2objectsperblock;
  /* No memory has been allocated. */
  pool->totalmemory = 0;
  /* The upper tier array has not been allocated yet. */
  pool->toparray = (char **) NULL;
  pool->toparraylen = 0;

  /* Ready all indices to be allocated. */
  arraypoolrestart(pool);
}

/*****************************************************************************/
/*                                                                           */
/*  arraypooldeinit()   Free to the operating system all memory taken by an  */
/*                      arraypool.                                           */
/*                                                                           */
/*  pool:  The arraypool to free.                                            */
/*                                                                           */
/*****************************************************************************/

void arraypooldeinit(struct arraypool *pool)
{
  arraypoolulong i;

  /* Has anything been allocated at all? */
  if (pool->toparray != (char **) NULL) {
    /* Walk through the top tier array. */
    for (i = 0; i < pool->toparraylen; i++) {
      /* Check every top-tier pointer; NULLs may be scattered randomly. */
      if (pool->toparray[i] != (char *) NULL) {
        /* Free a second-tier block. */
        starfree((void *) pool->toparray[i]);
      }
    }
    /* Free the top-tier array. */
    starfree((void *) pool->toparray);
  }

  /* The upper tier array is no longer allocated. */
  pool->toparray = (char **) NULL;
  pool->toparraylen = 0;
  pool->objects = 0;
  pool->totalmemory = 0;
}

/*****************************************************************************/
/*                                                                           */
/*  arraypoolsecondtier()   Return (and perhaps create) the second-tier      */
/*                          block containing the object with a given index.  */
/*                                                                           */
/*  This procedure takes care of allocating or resizing the top-tier array   */
/*  if necessary, and of allocating the second-tier block if it hasn't yet   */
/*  been allocated.                                                          */
/*                                                                           */
/*  pool:  The arraypool containing the object.                              */
/*  index:  The index of the object sought.                                  */
/*                                                                           */
/*  Returns a pointer to the beginning of the second-tier block.  (Not to    */
/*    the object with the specified index; just the block containing it.)    */
/*                                                                           */
/*****************************************************************************/

char *arraypoolsecondtier(struct arraypool *pool,
                          arraypoolulong index)
{
  char **newarray;
  char *secondtier;
  arraypoolulong newsize;
  arraypoolulong topindex;
  arraypoolulong i;

  /* Compute the index in the top-tier array (upper bits). */
  topindex = index >> pool->log2objectsperblock;
  /* Does the top-tier array need to be allocated or resized? */
  if (pool->toparray == (char **) NULL) {
    /* Allocate a top-tier array big enough to hold `topindex' (plus */
    /*   some slack), and NULL out its contents.                     */
    newsize = topindex + TOPARRAYSTARTSIZE;
    pool->toparray = (char **) starmalloc((size_t) (newsize * sizeof(char *)));
    pool->toparraylen = newsize;
    for (i = 0; i < newsize; i++) {
      pool->toparray[i] = (char *) NULL;
    }

    /* Account for the memory. */
    pool->totalmemory = newsize * (arraypoolulong) sizeof(char *);
  } else if (topindex >= pool->toparraylen) {
    /* Resize the top-tier array, making sure it holds `topindex'. */
    newsize = TOPRESIZEFACTOR * pool->toparraylen;
    if (topindex >= newsize) {
      newsize = topindex + TOPARRAYSTARTSIZE;
    }

    /* Allocate the new array, copy the contents, NULL out the rest, and */
    /*   free the old array.                                             */
    newarray = (char **) starmalloc((size_t) (newsize * sizeof(char *)));
    for (i = 0; i < pool->toparraylen; i++) {
      newarray[i] = pool->toparray[i];
    }
    for (i = pool->toparraylen; i < newsize; i++) {
      newarray[i] = (char *) NULL;
    }
    starfree(pool->toparray);

    /* Account for the memory. */
    pool->totalmemory += (newsize - pool->toparraylen) * sizeof(char *);

    pool->toparray = newarray;
    pool->toparraylen = newsize;
  }

  /* Find the second-tier block, or learn that it hasn't been allocated yet. */
  secondtier = pool->toparray[topindex];
  if (secondtier == (char *) NULL) {
    /* Allocate a second-tier block at this index. */
    secondtier = (char *) starmalloc((size_t) (pool->objectsperblock *
                                               pool->objectbytes));
    pool->toparray[topindex] = secondtier;
    /* Account for the memory. */
    pool->totalmemory += pool->objectsperblock * pool->objectbytes;
  }

  /* Return a pointer to the second-tier block. */
  return secondtier;
}

/*****************************************************************************/
/*                                                                           */
/*  arraypoolforcelookup()   A "dereferencing" operation:  return the        */
/*                           pointer to the object with a given index,       */
/*                           creating the object if it doesn't yet exist.    */
/*                                                                           */
/*  If memory does not yet exist for the object with the given index, this   */
/*  procedure allocates a second-tier block with room for the object.  (The  */
/*  new object's memory is not initialized in any way.)  Subsequent calls    */
/*  with the same index will always return the same object.                  */
/*                                                                           */
/*  The object with the given index is NOT allocated to the client by the    */
/*  arraypool, and the object may be subsequently returned by a call to      */
/*  arraypoolnewindex() or arraypoolnewptr(), perhaps causing an object to   */
/*  have two conflicting uses.  Generally, those procedures do not mix       */
/*  easily with this one, but they can be mixed with enough care.            */
/*                                                                           */
/*  pool:  The arraypool containing the object.                              */
/*  index:  The index of the object sought.                                  */
/*                                                                           */
/*  Returns a pointer to the object.                                         */
/*                                                                           */
/*****************************************************************************/

void *arraypoolforcelookup(struct arraypool *pool,
                           arraypoolulong index)
{
  /* Find the second-tier block and compute a pointer to the object with the */
  /*   given index.  Note that `objectsperblock' is a power of two, so the   */
  /*   & operation is a bit mask that preserves the lower bits.              */
  return (void *) (arraypoolsecondtier(pool, index) +
                   (index & (pool->objectsperblock - 1)) * pool->objectbytes);
}

/*****************************************************************************/
/*                                                                           */
/*  arraypoollookup()   A "dereferencing" operation:  return the pointer to  */
/*                      the object with a given index, or NULL if the        */
/*                      object's second-tier block doesn't yet exist.        */
/*                                                                           */
/*  Note that this procedure cannot tell whether an object with the given    */
/*  index has been allocated by the arraypool or initialized by the client   */
/*  yet; it can only tell whether memory has been allocated for the second-  */
/*  tier block that contains the object.                                     */
/*                                                                           */
/*  pool:  The arraypool containing the object.                              */
/*  index:  The index of the object sought.                                  */
/*                                                                           */
/*  Returns a pointer to the object if its block exists; NULL otherwise.     */
/*                                                                           */
/*****************************************************************************/

void *arraypoollookup(struct arraypool *pool,
                      arraypoolulong index)
{
  char *secondtier;
  arraypoolulong topindex;

  /* Has the top-tier array been allocated yet? */
  if (pool->toparray == (char **) NULL) {
    return (void *) NULL;
  }

  /* Compute the index in the top-tier array (upper bits). */
  topindex = index >> pool->log2objectsperblock;
  /* Does the top-tier index fit in the top-tier array? */
  if (topindex >= pool->toparraylen) {
    return (void *) NULL;
  }

  /* Find the second-tier block, or learn that it hasn't been allocated yet. */
  secondtier = pool->toparray[topindex];
  if (secondtier == (char *) NULL) {
    return (void *) NULL;
  }

  /* Compute a pointer to the object with the given index.  Note that        */
  /*   `objectsperblock' is a power of two, so the & operation is a bit mask */
  /*   that preserves the lower bits.                                        */
  return (void *) (secondtier +
                   (index & (pool->objectsperblock - 1)) * pool->objectbytes);
}

/*****************************************************************************/
/*                                                                           */
/*  arraypoolfastlookup()   A fast, unsafe "dereferencing" operation:        */
/*                          return the pointer to the object with a given    */
/*                          index.  The object's second-tier block must have */
/*                          been allocated.                                  */
/*                                                                           */
/*  Use this procedure only for indices that have previously been allocated  */
/*  with arraypoolnewindex() or "dereferenced" with arraypoolforcelookup().  */
/*  WARNING:  fails catastrophically, probably with a segmentation fault, if */
/*  the index's second-tier block doesn't yet exist.                         */
/*                                                                           */
/*  Implemented as a macro to meet your need for speed.                      */
/*                                                                           */
/*  pool:  The arraypool containing the object.                              */
/*         Type (struct arraypool *).                                        */
/*  index:  The index of the object sought.                                  */
/*          Type (arraypoolulong).                                           */
/*                                                                           */
/*  Returns a pointer to the object if its block exists; might crash         */
/*    otherwise.                                                             */
/*    Type (void *).                                                         */
/*                                                                           */
/*****************************************************************************/

/* Dereference the top tier `toparray' with the upper bits to find the  */
/*   second-tier bock, then add an offset computed from the lower bits. */

#define arraypoolfastlookup(pool, index)  \
  (void *) ((pool)->toparray[(index) >> (pool)->log2objectsperblock] +  \
            ((index) & ((pool)->objectsperblock - 1)) * (pool)->objectbytes)

/*****************************************************************************/
/*                                                                           */
/*  arraypoolnewptr()   Allocate space for a fresh object from an arraypool. */
/*                                                                           */
/*  Returns an object that was not already allocated, or has been freed      */
/*  since it was last allocated.  Be forewarned that this procedure is not   */
/*  aware of objects that have been accessed by arraypoolforcelookup(), and  */
/*  may allocate them, possibly resulting in conflicting uses of an object.  */
/*                                                                           */
/*  pool:  The arraypool to allocate an object from.                         */
/*                                                                           */
/*  Returns a pointer to a fresh object.                                     */
/*                                                                           */
/*****************************************************************************/

void *arraypoolnewptr(struct arraypool *pool)
{
  void *newobject;

  /* Check if any freed objects have not yet been reallocated. */
  if (pool->deadobjectstack != (void *) NULL) {
    /* Reallocate an object from the stack of dead objects. */
    newobject = pool->deadobjectstack;
    /* Remove the object from the stack. */
    pool->deadobjectstack = * (void **) newobject;
  } else {
    /* Allocate an object at index `firstvirgin'. */
    newobject = (void *) (arraypoolsecondtier(pool, pool->firstvirgin) +
                          (pool->firstvirgin & (pool->objectsperblock - 1)) *
                          pool->objectbytes);
    pool->firstvirgin++;
  }
  pool->objects++;

  return newobject;
}

/*****************************************************************************/
/*                                                                           */
/*  arraypoolfreeptr()   Deallocate an object, freeing its space for reuse.  */
/*                                                                           */
/*  The object's memory is not freed to the operating system; rather, the    */
/*  object is stored in a stack so it can be reallocated later by            */
/*  arraypoolnewptr().  (It cannot be reallocated by arraypoolnewindex(),    */
/*  though.)                                                                 */
/*                                                                           */
/*  WARNING:  Use this procedure only if the arraypool was initialized with  */
/*  alloctype == 2!  Not compatible with an alloctype of 0 or 1.             */
/*                                                                           */
/*  pool:  The arraypool the object was allocated from.                      */
/*  dyingobject:  A pointer to the object to deallocate.  Must be in `pool'! */
/*                                                                           */
/*****************************************************************************/

void arraypoolfreeptr(struct arraypool *pool,
                      void *dyingobject)
{
  /* Store the object on the stack of dead objects for later reuse. */
  * (void **) dyingobject = pool->deadobjectstack;
  pool->deadobjectstack = dyingobject;
  pool->objects--;
}

/*****************************************************************************/
/*                                                                           */
/*  arraypoolnewindex()   Allocate space for a fresh object from an          */
/*                        arraypool.                                         */
/*                                                                           */
/*  Returns an object that was not already allocated, or has been freed      */
/*  since it was last allocated.  Be forewarned that this procedure is not   */
/*  aware of objects that have been accessed by arraypoolforcelookup(), and  */
/*  may allocate them, possibly resulting in conflicting uses of an object.  */
/*                                                                           */
/*  From a fresh pool, indices are allocated starting from zero.             */
/*                                                                           */
/*  pool:  The arraypool to allocate an object from.                         */
/*  newptr:  If this pointer is not NULL, a pointer to the new object is     */
/*    written at the location that `newptr' points to.                       */
/*                                                                           */
/*  Returns the index of a fresh object.                                     */
/*                                                                           */
/*****************************************************************************/

arraypoolulong arraypoolnewindex(struct arraypool *pool,
                                 void **newptr)
{
  void *newobject;
  arraypoolulong newindex;

  /* Check if any freed objects have not yet been reallocated. */
  if (pool->deadindexstack != NOTAPOOLINDEX) {
    /* Reallocate an object (by index) from the stack of dead objects. */
    newindex = pool->deadindexstack;
    /* Find a pointer to the object. */
    newobject = arraypoollookup(pool, newindex);
    /* Memory should already exist for this index. */
    if (newobject == (void *) NULL) {
      printf("Internal error in arraypoolnewindex():\n");
      printf("  Illegal index on stack of deallocated objects.\n");
      internalerror();
    }
    /* Remove the object from the stack. */
    pool->deadindexstack = * (arraypoolulong *) newobject;
  } else {
    /* Allocate an object at index `firstvirgin'. */
    newindex = pool->firstvirgin;
    newobject = (void *) (arraypoolsecondtier(pool, pool->firstvirgin) +
                          (pool->firstvirgin & (pool->objectsperblock - 1)) *
                          pool->objectbytes);
    pool->firstvirgin++;
  }
  pool->objects++;

  /* If `newptr' is not NULL, use it to return a pointer to the object. */
  if (newptr != (void **) NULL) {
    *newptr = newobject;
  }
  return newindex;
}

/*****************************************************************************/
/*                                                                           */
/*  arraypoolfreeindex()   Deallocate an object, freeing its index and space */
/*                         for reuse.                                        */
/*                                                                           */
/*  The object's memory is not freed to the operating system; rather, the    */
/*  object is stored in a stack so it can be reallocated later by            */
/*  arraypoolnewindex().  (It cannot be reallocated by arraypoolnewptr(),    */
/*  though.)                                                                 */
/*                                                                           */
/*  WARNING:  Use this procedure only if the arraypool was initialized with  */
/*  alloctype == 1!  Not compatible with an alloctype of 0 or 2.             */
/*                                                                           */
/*  pool:  The arraypool the object was allocated from.                      */
/*  dyingindex:  The index of the object to deallocate.                      */
/*                                                                           */
/*****************************************************************************/

void arraypoolfreeindex(struct arraypool *pool,
                        arraypoolulong dyingindex)
{
  void *dyingptr;

  /* Find a pointer to the object. */
  dyingptr = arraypoollookup(pool, dyingindex);
  if (dyingptr == (void *) NULL) {
    printf("Internal error in arraypoolfreeindex():\n");
    printf("  Attempt to free an unallocated index.\n");
    internalerror();
  }

  /* Store the index on the stack of dead objects for later reuse. */
  * (arraypoolulong *) dyingptr = pool->deadindexstack;
  pool->deadindexstack = dyingindex;
  pool->objects--;
}

/*****************************************************************************/
/*                                                                           */
/*  arraypoolallocated()   Return the maximum number of allocated objects.   */
/*                                                                           */
/*  Returns the greatest number of objects that have been allocated from the */
/*  arraypool at once.  This number is one greater than the greatest index   */
/*  of any object ever allocated from the arraypool.  Therefore, it can be   */
/*  used to loop through all the objects in the pool--if no object has been  */
/*  freed, or you are clever enough to be able to distinguish between freed  */
/*  items and allocated ones.                                                */
/*                                                                           */
/*  pool:  The arraypool in question.                                        */
/*                                                                           */
/*  Returns the maximum number of objects currently allocated in `pool'.     */
/*                                                                           */
/*****************************************************************************/

arraypoolulong arraypoolallocated(struct arraypool *pool)
{
  return pool->firstvirgin;
}

/*****************************************************************************/
/*                                                                           */
/*  arraypoolbytes()   Returns the number of bytes of dynamic memory used by */
/*                     the tiered array memory pool.                         */
/*                                                                           */
/*  The result sums all the bytes dynamically allocated on the heap for the  */
/*  allocpool, including the top tier array and the second-tier blocks.      */
/*  Does not include the size of the `struct arraypool', which is presumably */
/*  part of some other object and accounted for there.  Note that arraypools */
/*  only release memory to the operating system when arraypooldeinit() is    */
/*  called, so the result is the _maximum_ number of bytes allocated since   */
/*  the initiating call to arraypoolinit().                                  */
/*                                                                           */
/*  pool:  The arraypool in question.                                        */
/*                                                                           */
/*  Returns the number of dynamically allocated bytes in `pool'.             */
/*                                                                           */
/*****************************************************************************/

arraypoolulong arraypoolbytes(struct arraypool *pool)
{
  return pool->totalmemory;
}

/**                                                                         **/
/**                                                                         **/
/********* Tiered array memory pool routines end here                *********/


/******** Proximity-based memory pool management routines begin here  ********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  Proximity-based memory pools (struct proxipool)                          */
/*                                                                           */
/*  A proximity-based memory pool is a memory allocator (for objects of a    */
/*  single size) which divides memory into separate pools, each with a       */
/*  different "allocation index."  The idea is that objects that are         */
/*  geometrically close to each other are likely to have the same allocation */
/*  index, and therefore be close to each other--both close in memory, and   */
/*  close in the space of "tags."  Each object is assigned a distance tag,   */
/*  which can be used like an array index to address the object.  The reason */
/*  I want proximate objects to have proximate tags is so that tags can be   */
/*  compressed well in the triangulation data structures.                    */
/*                                                                           */
/*  A proxipool is a tiered array.  (You should read the documentation for   */
/*  tiered arrays, "struct arraypool", before reading on.)  There are some   */
/*  important differences, of course.  Each second-tier block in a proxipool */
/*  is called a "minipool," and is assigned to a single allocation index.    */
/*  All the objects in a second-tier block have the same allocation index;   */
/*  this is the mechanism for maintaining memory proximity and tag           */
/*  proximity.  Each allocation index has a set of minipools associated with */
/*  it; this set is called a "poolpool" because it is a pool of minipools.   */
/*                                                                           */
/*  To further improve tag proximity, tags are allocated to allocation       */
/*  indices in "groups" of minipools.  For example, when the very first      */
/*  object is allocated, receiving tag 0, the proxipool will allocate a      */
/*  minipool for that object's allocation index.  Moreover, the next seven   */
/*  or so minipools' worth of tags will also be reserved for the allocation  */
/*  index--though the seven minipools are not allocated until (and unless)   */
/*  they are needed.                                                         */
/*                                                                           */
/*  Objects in a proxipool can be freed for reuse.  Each minipool maintains  */
/*  its own linked list of freed objects in the minipool (as opposed to      */
/*  having one global linked list for each allocation index).  This helps to */
/*  keep memory accesses more local.                                         */
/*                                                                           */
/*  When an object that resides in a full minipool is freed, its memory is   */
/*  available again for new objects with the same allocation index.  For     */
/*  each allocation index, a poolpool record maintains a linked list of all  */
/*  the minipools that belong to that allocation index and have free space   */
/*  available to allocate.  When an object is freed in a full minipool, the  */
/*  minipool adds itself to the end of the poolpool's linked list.           */
/*                                                                           */
/*  The poolpool records are stored in an arraypool (tiered array).          */
/*                                                                           */
/*  A new object is allocated as follows.  Find the poolpool associated with */
/*  the object's allocation index.  If the poolpool's linked list of         */
/*  minipools is not empty, allocate the object in the first minipool on the */
/*  list.  If the minipool is now full, remove it from the linked list.      */
/*  On the other hand, if the linked list was empty, allocate a new          */
/*  minipool--from the same group as the last allocated minipool if that     */
/*  group is not exhausted; otherwise, from a newly allocated group.         */
/*                                                                           */
/*  A proxipool is also built on an arraypool, in the sense that the objects */
/*  allocated from a proxipool live in the memory of an arraypool.  However, */
/*  the proxipool manages each second-tier block (minipool) itself, so it    */
/*  creates an arraypool having only one "object" per second-tier block,     */
/*  that "object" being a minipool.  Each minipool has a header at the       */
/*  beginning of the second-tier block, followed by a sequence of objects,   */
/*  which are managed by the minipool.                                       */
/*                                                                           */
/*  Some invariants of proxipools:                                           */
/*                                                                           */
/*  - Each object is allocated from a minipool that has the same allocation  */
/*    index as the object.                                                   */
/*                                                                           */
/*  - Every minipool with an unallocated slot appear in its poolpool's       */
/*    linked list.                                                           */
/*                                                                           */
/*  - No full minipool appears in a poolpool's linked list.                  */
/*                                                                           */
/*  - A new minipool is allocated only when a new object's allocation index  */
/*    indexes a poolpool whose linked list of minipools is empty.            */
/*                                                                           */
/*  - Minipools whose tags fall into the same "group" have the same          */
/*    allocation index.                                                      */
/*                                                                           */
/*  - A poolpool reserves only one group at a time, and does not reserve     */
/*    another group until it has filled all the minipools in the first       */
/*    group.                                                                 */
/*                                                                           */
/*  Public interface:                                                        */
/*  typedef proxipoolulong   Unsigned allocation index.                      */
/*  typedef tag   Unsigned tag for indexing objects in the memory pool.      */
/*  struct proxipool   Proximity-based memory pool object.                   */
/*  void proxipoolinit(pool, objectbytes1, objectbytes2, verbose)            */
/*    Initialize a proxipool for allocation of objects.                      */
/*  void proxipoolrestart(pool)   Deallocate all the objects (not to OS).    */
/*  void proxipooldeinit(pool)   Free a proxipool's memory to the OS.        */
/*  void *proxipooltag2object(pool, searchtag)   Unsafe dereference; fast    */
/*    macro.                                                                 */
/*  void *proxipooltag2object2(pool, searchtag)   Unsafe dereference to      */
/*    supplementary object; fast macro.                                      */
/*  proxipoolulong proxipooltag2allocindex(pool, searchtag)   Unsafe lookup  */
/*    of the allocation index that a tag is associated with; fast macro.     */
/*  tag proxipooliterate(pool, thistag)   Iterate over the allocated tags.   */
/*  tag proxipoolnew(pool, allocindex, outobject)   Allocate an object.      */
/*  void proxipoolfree(pool, killtag)   Deallocate tag for reuse.            */
/*  arraypoolulong proxipoolobjects(pool)   Return # of objects in pool.     */
/*  arraypoolulong proxipoolbytes(pool)   Return bytes of dynamic memory     */
/*    used by the proxipool.                                                 */
/*                                                                           */
/*  For internal use only:                                                   */
/*  NOTATAG                                                                  */
/*  NOTAMINIINDEX                                                            */
/*  OBJECTSPERMINI                                                           */
/*  LOG2OBJECTSPERMINI                                                       */
/*  MINISPERGROUP                                                            */
/*  LOG2POOLPOOLSPERBLOCK                                                    */
/*  typedef miniindex                                                        */
/*  struct minipoolheader                                                    */
/*  struct poolpool                                                          */
/*  void proxipoolrestartmini(pool, mini)                                    */
/*  struct minipoolheader *proxipooltag2mini(pool, searchtag)                */
/*  void proxipoolinitpoolpools(pool, endindex)                              */
/*                                                                           */
/*****************************************************************************/


/*  `proxipoolulong' is the type of (unsigned) integer used for allocation   */
/*  indices, here and in the allocation map (allocmap).  Its length can be   */
/*  changed.  A shorter choice consumes less memory; a longer choice         */
/*  increases the number of allocation indices that can exist.               */
/*                                                                           */
/*  In many cases, it might be possible to use a 32-bit proxipoolulong, even */
/*  if 64 bits are needed to index the vertices and other objects.  However, */
/*  proxipoolulongs take up such a tiny proportion of memory, it's probably  */
/*  not worth the risk.  On the other hand, it doesn't make sense to make    */
/*  proxipoolulongs longer than arraypoolulongs, because the allocation      */
/*  indices index objects in an arraypool.                                   */
/*                                                                           */
/*  The `tag' type is used specifically to denote tags, which are internal   */
/*  indices chosen to compress well.  A `miniindex' type indexes an object   */
/*  within a single minipool, and is kept as short as possible to minimize   */
/*  space in minipoolheaders; but a `miniindex' must be at least             */
/*  LOG2OBJECTSPERMINI + 1 bits long.                                        */

typedef arraypoolulong proxipoolulong;
typedef arraypoolulong tag;
typedef unsigned short miniindex;


/*  NOTATAG is a tag denoting no object in a proxipool.                      */

#define NOTATAG ((tag) ~0)

/*  NOTAMINIINDEX is an index denoting no freed object within a minipool.    */

#define NOTAMINIINDEX ((miniindex) ~0)


/*  The number of objects in a minipool.  (A minipool is the smallest unit   */
/*  of objects allocated at one time.)  Must be a power of 2.                */

#define OBJECTSPERMINI 1024

/*  The following MUST be the base-2 logarithm of the above.  If you change  */
/*  one, change the other to match.  Also, make sure that a `miniindex' can  */
/*  hold this many bits plus one.                                            */

#define LOG2OBJECTSPERMINI 10

/*  The number of minipools that are clustered together in a group, all      */
/*  associated with the same allocation index.  Must be a power of 2.        */

#define MINISPERGROUP 8

/*  LOG2POOLPOOLSPERBLOCK is the base-2 logarithm of the number of poolpools */
/*  allocated at a time.                                                     */

#define LOG2POOLPOOLSPERBLOCK 8


/*  A minipool is a block of OBJECTSPERMINI objects.  It consists of one     */
/*  minipoolheader, then OBJECTSPERMINI contiguous objects, then optionally  */
/*  OBJECTSPERMINI contiguous "supplementary" objects that are paired with   */
/*  the first OBJECTSPERMINI objects.  Typically, the supplementary objects  */
/*  contain information that is rarely accessed, and so ought to go into     */
/*  separate pages of virtual memory.                                        */
/*                                                                           */
/*  The minipoolheader contains information about the minipool.  To keep     */
/*  track of objects that are free to be allocated, `firstvirgin' indicates  */
/*  the index of the first object in the minipool that has never been        */
/*  allocated (implying that the objects that follow it are virgins too),    */
/*  and `freestack' is the head of a linked stack of objects in the minipool */
/*  that have been freed.  `object1block' and `object2block' indicate where  */
/*  the two blocks of OBJECTSPERMINI objects start.                          */
/*                                                                           */
/*  One goal is that objects that are spatially close should be close in     */
/*  memory too.  Therefore, each minipool has an allocation index,           */
/*  `allocindex'.  Typically, geometric objects like vertices are assigned   */
/*  allocation indices based on their positions.  For each alloction index,  */
/*  there is a structure of type `struc poolpool' (stored in an array of     */
/*  poolpools) that maintains a linked list of all the minipools associated  */
/*  with that allocation index.  `nextminifree' is the next minipool in the  */
/*  linked list of minipools that have free space.  (There is one such       */
/*  linked list for each allocation index.)                                  */

struct minipoolheader {
  char *object1block;    /* Pointer to the block of objects in the minipool. */
  char *object2block;          /* Optional pointer to supplementary objects. */
  proxipoolulong allocindex;                       /* Index of the poolpool. */
  tag nextminifree;     /* Next in linked list of minipools with free space. */
  miniindex firstvirgin;        /* First never-allocated object in minipool. */
  miniindex freestack; /* Head of linked stack of freed objects in minipool. */
};

/*  A poolpool is a pool of minipools associated with one allocation index.  */
/*  It references a list of minipools that have free space, through          */
/*  `freelisthead' and `freelisttail'.  It also references a group in which  */
/*  further minipools can be allocated.  `mygroup' specifies a group by      */
/*  tagging the next minipool that will be allocated in the group.           */

struct poolpool {
  tag freelisthead;            /* Head of list of minipools with free space. */
  tag freelisttail;            /* Tail of list of minipools with free space. */
  tag mygroup;                 /* Next minipool to be allocated in my group. */
};

/*  A proxipool is a pool from which objects can be allocated.  With the     */
/*  help of an allocation tree, it allocates objects so that they are close  */
/*  in memory to objects they are spatially close to.  `objectbytes1' is the */
/*  length of each object in bytes, and `objectbytes2' is the length of the  */
/*  supplementary information (if any) associated with each object.          */
/*  `block1offset' is the offset (in bytes) at which the first object        */
/*  appears after the beginning of each minipoolheader, and `block2offset'   */
/*  is the offset at which the first supplementary object appears.           */
/*  `minipoolsize' is the size (in bytes) of each minipool, including one    */
/*  minipoolheader, OBJECTSPERMINI objects, and perhaps OBJECTSPERMINI       */
/*  supplementary objects.                                                   */
/*                                                                           */
/*  `minipoolarray' is a tiered array of minipools.  `objects' is the number */
/*  of objects currently allocated from the proxipool, and `maxobjects' is   */
/*  the largest number that have been allocated at any one time.             */
/*  `nextgroup' is the first tag of the first minipool of the group of       */
/*  minipools that will be allocated next.                                   */
/*                                                                           */
/*  For each allocation index, each proxipool has a poolpool (pool of        */
/*  minipools) from which to allocate objects.  `poolpools' is an arraypool  */
/*  used to map allocation indices to poolpools.  `nextinitindex' is the     */
/*  index of the first poolpool that has not yet been initialized.           */
/*                                                                           */
/*  The number `verbosity' indicates how much debugging information to       */
/*  print, from none (0) to lots (4+).                                       */

struct proxipool {
  size_t objectbytes1;                    /* Size of one object in the pool. */
  size_t objectbytes2;                      /* Size of supplementary object. */
  size_t block1offset;                /* Offset of first object from header. */
  size_t block2offset;              /* Offset of first supplementary object. */
  size_t minipoolsize;            /* Size of one minipool, including header. */

  struct arraypool minipoolarray;              /* Tiered array of minipools. */
  arraypoolulong objects;          /* Number of currently allocated objects. */
  arraypoolulong maxobjects;              /* Maximum allocated objects ever. */
  tag nextgroup;                 /* Next group of minipools to be allocated. */

  struct arraypool poolpools;                  /* Tiered array of poolpools. */
  proxipoolulong nextinitindex;   /* First uninitialized index in the array. */
  int verbosity;                /* Amount of debugging information to print. */
};


/*****************************************************************************/
/*                                                                           */
/*  proxipoolrestartmini()   Reset a minipool to a pristine state.           */
/*                                                                           */
/*  The minipool is set so that it contains no objects, and all its space    */
/*  is available for allocating.                                             */
/*                                                                           */
/*  pool:  The proxipool containing the minipool.                            */
/*  mini:  The minipool to restart.                                          */
/*                                                                           */
/*****************************************************************************/

void proxipoolrestartmini(struct proxipool *pool,
                          struct minipoolheader *mini)
{
  /* Give the minipool pointers to its objects. */
  mini->object1block = ((char *) mini) + pool->block1offset;
  mini->object2block = pool->objectbytes2 > 0 ?
    ((char *) mini) + pool->block2offset : (char *) NULL;

  /* The minipool is not on any poolpool's list. */
  mini->nextminifree = NOTATAG;
  /* The minipool is associated with the default poolpool (index zero). */
  mini->allocindex = 0;
  /* The pool contains no objects. */
  mini->firstvirgin = 0;
  mini->freestack = NOTAMINIINDEX;
}

/*****************************************************************************/
/*                                                                           */
/*  proxipoolrestart()   Deallocate all objects in a proxipool.              */
/*                                                                           */
/*  The pool is returned to its starting state, except that no memory is     */
/*  freed to the operating system.  Rather, the previously allocated         */
/*  minipools are ready to be reused.                                        */
/*                                                                           */
/*  pool:  The proxipool to restart.                                         */
/*                                                                           */
/*****************************************************************************/

void proxipoolrestart(struct proxipool *pool)
{
  struct minipoolheader *mini;
  arraypoolulong maxindex;
  arraypoolulong i;

  /* Restart all the allocated minipools. */
  maxindex = (arraypoolulong) (pool->nextgroup >> LOG2OBJECTSPERMINI);
  for (i = 0; i < maxindex; i++) {
    mini = (struct minipoolheader *) arraypoollookup(&pool->minipoolarray, i);
    if (mini != (struct minipoolheader *) NULL) {
      proxipoolrestartmini(pool, mini);
    }
  }

  /* Free all the poolpools for reuse. */
  arraypoolrestart(&pool->poolpools);

  /* No objects have been allocated. */
  pool->objects = 0;
  /* The next group of minipools that will be allocated starts with tag */
  /*   zero.                                                            */
  pool->nextgroup = 0;
  /* No poolpool has been initialized. */
  pool->nextinitindex = 0;
}

/*****************************************************************************/
/*                                                                           */
/*  proxipoolinit()   Initialize a pool of memory for allocation of objects. */
/*                                                                           */
/*  Before a proxipool may be used, it must be initialized by this           */
/*  procedure.  After initialization, tags (with associated memory) can be   */
/*  allocated and freed in a proxipool.  proxipoolinit() does not allocate   */
/*  any memory from the operating system itself.                             */
/*                                                                           */
/*  The `pool' allocates space for objects of size `objectbytes1'.  Each     */
/*  object may also have a supplementary object with size `objectbytes2'.    */
/*  The supplementary objects are used to store information that is used     */
/*  infrequently and thus is best stored in different memory pages than the  */
/*  primary objects.                                                         */
/*                                                                           */
/*  Don't call this procedure on a proxipool that has already been           */
/*  initialized (by this procedure), unless you call proxipooldeinit() on    */
/*  it first.  You will leak memory.  Also see proxipoolrestart().           */
/*                                                                           */
/*  pool:  The proxipool to initialize.                                      */
/*  objectbytes1:  The size, in bytes, of the objects.                       */
/*  objectbytes2:  Size of the supplementary objects.  If zero, no space is  */
/*    allocated for these.                                                   */
/*  verbose:  How much debugging information proxipool procedures should     */
/*    print, from none (0) to lots (4+).                                     */
/*                                                                           */
/*****************************************************************************/

void proxipoolinit(struct proxipool *pool,
                   size_t objectbytes1,
                   size_t objectbytes2,
                   int verbose)
{
  size_t maxword;

  /* Find the size of the largest data object:  pointer, real, or long. */
  maxword = sizeof(arraypoolulong) > sizeof(void *) ?
            sizeof(arraypoolulong) : sizeof(void *);
  maxword = sizeof(starreal) > maxword ? sizeof(starreal) : maxword;

  /* The number of bytes occupied by an object. */
  pool->objectbytes1 = objectbytes1 > sizeof(miniindex) ?
                       objectbytes1 : sizeof(miniindex);
  /* The number of bytes occupied by a subsidiary object. */
  pool->objectbytes2 = objectbytes2 > 0 ? objectbytes2 : 0;

  /* The objects in a minipool begin `block1offset' bytes after the    */
  /*   minipoolheader.  It's rounded up to be a multiple of `maxword'. */
  pool->block1offset = ((sizeof(struct minipoolheader) - 1) / maxword + 1) *
                       maxword;
  /* The subsidiary objects in a minipool begin `block2offset' bytes after */
  /*   the minipoolheader.  It's rounded up to be a multiple of `maxword'. */
  pool->block2offset = ((pool->block1offset +
                         OBJECTSPERMINI * pool->objectbytes1 - 1) / maxword +
                        1) * maxword;
  /* `minipoolsize' is the total number of bytes in one minipool. */
  pool->minipoolsize = ((pool->block2offset +
                         OBJECTSPERMINI * pool->objectbytes2 - 1) / maxword +
                        1) * maxword;

  pool->verbosity = verbose;
  /* No objects in the pool yet. */
  pool->maxobjects = 0;

  /* Create a teired array of minipools.  Note that there is only one        */
  /*   minipool per block of the tiered array.  This is because I don't want */
  /*   to allocate memory for minipools that aren't being used, and because  */
  /*   the proxipool manages multiple objects within each minipool           */
  /*   differently than the arraypool manages objects within a block.        */
  arraypoolinit(&pool->minipoolarray, (arraypoolulong) pool->minipoolsize,
                (arraypoolulong) 0, 0);

  /* Create an array of poolpools. */
  arraypoolinit(&pool->poolpools, (arraypoolulong) sizeof(struct poolpool),
                (arraypoolulong) LOG2POOLPOOLSPERBLOCK, 0);

  proxipoolrestart(pool);
}

/*****************************************************************************/
/*                                                                           */
/*  proxipooldeinit()   Free to the operating system all memory taken by a   */
/*                      proxipool.                                           */
/*                                                                           */
/*  pool:  The proxipool to free.                                            */
/*                                                                           */
/*****************************************************************************/

void proxipooldeinit(struct proxipool *pool)
{
  /* Free the array of minipools. */
  arraypooldeinit(&pool->minipoolarray);
  /* Free the array of poolpools. */
  arraypooldeinit(&pool->poolpools);
}

/*****************************************************************************/
/*                                                                           */
/*  proxipooltag2mini()   Map a tag to the minipool it indexes.              */
/*                                                                           */
/*  WARNING:  fails catastrophically, probably with a segmentation fault, if */
/*  the tag's minipool doesn't yet exist.                                    */
/*                                                                           */
/*  Implemented as a macro to meet your need for speed.                      */
/*                                                                           */
/*  pool:  The proxipool in which to find a minipool.                        */
/*         Type (struct proxipool *).                                        */
/*  searchtag:  The tag whose minipool is sought.                            */
/*              Type (tag).                                                  */
/*                                                                           */
/*  Returns the minipool that contains the object with the given tag.  Might */
/*    crash if no such minipool has been allocated yet.                      */
/*    Type (struct minipoolheader *).                                        */
/*                                                                           */
/*****************************************************************************/

#define proxipooltag2mini(pool, searchtag)  \
  ((struct minipoolheader *)  \
   arraypoolfastlookup(&(pool)->minipoolarray,  \
                       (searchtag) >> LOG2OBJECTSPERMINI))

/*****************************************************************************/
/*                                                                           */
/*  proxipooltag2object()   Map a tag to the object it indexes.              */
/*                                                                           */
/*  WARNING:  fails catastrophically, probably with a segmentation fault, if */
/*  the tag's minipool doesn't yet exist.                                    */
/*                                                                           */
/*  Implemented as a macro to meet your need for speed.                      */
/*                                                                           */
/*  pool:  The proxipool in which to find an object.                         */
/*         Type (struct proxipool *).                                        */
/*  searchtag:  The tag whose object is sought.                              */
/*              Type (tag).                                                  */
/*                                                                           */
/*  Returns a pointer to the object.  Might crash if the tag has not been    */
/*    allocated yet.                                                         */
/*    Type (void *).                                                         */
/*                                                                           */
/*****************************************************************************/

#define proxipooltag2object(pool, searchtag)  \
  ((void *) (proxipooltag2mini(pool, searchtag)->object1block +  \
             (searchtag & (OBJECTSPERMINI - 1)) * (pool)->objectbytes1))

/*****************************************************************************/
/*                                                                           */
/*  proxipooltag2object2()   Map a tag to the supplementary object it        */
/*                           indexes.                                        */
/*                                                                           */
/*  WARNING:  fails catastrophically, probably with a segmentation fault, if */
/*  the tag's minipool doesn't yet exist.                                    */
/*                                                                           */
/*  Implemented as a macro to meet your need for speed.                      */
/*                                                                           */
/*  pool:  The proxipool in which to find a supplementary object.            */
/*         Type (struct proxipool *).                                        */
/*  searchtag:  The tag whose supplementary object is sought.                */
/*              Type (tag).                                                  */
/*                                                                           */
/*  Returns a pointer to the supplementary object.  Might crash if the tag   */
/*    has not been allocated yet.                                            */
/*    Type (void *).                                                         */
/*                                                                           */
/*****************************************************************************/

#define proxipooltag2object2(pool, searchtag)  \
  ((void *) (proxipooltag2mini(pool, searchtag)->object2block +  \
             (searchtag & (tag) (OBJECTSPERMINI - 1)) * (pool)->objectbytes2))

/*****************************************************************************/
/*                                                                           */
/*  proxipooltag2allocindex()   Map a tag to its allocation index.           */
/*                                                                           */
/*  WARNING:  fails catastrophically, probably with a segmentation fault, if */
/*  the tag's minipool doesn't yet exist.                                    */
/*                                                                           */
/*  Implemented as a macro to meet your need for speed.                      */
/*                                                                           */
/*  pool:  The proxipool in which an object is allocated.                    */
/*         Type (struct proxipool *).                                        */
/*  searchtag:  The tag of the object whose allocation index is sought.      */
/*              Type (tag).                                                  */
/*                                                                           */
/*  Returns the allocation index of the object.  Might crash if the tag has  */
/*    not been allocated yet.                                                */
/*    Type (proxipoolulong).                                                 */
/*                                                                           */
/*****************************************************************************/

#define proxipooltag2allocindex(pool, searchtag)  \
  (proxipooltag2mini(pool, searchtag)->allocindex)

/*****************************************************************************/
/*                                                                           */
/*  proxipooliterate()   Return the next allocated tag after a specified     */
/*                       tag.                                                */
/*                                                                           */
/*  This procedure is used to iterate over all the tags in a proxipool, from */
/*  smallest to largest, that have ever been allocated.  The iterator visits */
/*  tags that have been freed, as well as those that are still in use.       */
/*  It's up to the caller to distinguish objects that are not in use.        */
/*                                                                           */
/*  To get the iterator started (i.e. to find the first tag), call this      */
/*  procedure with `thistag' set to NOTATAG.                                 */
/*                                                                           */
/*  When there are no more tags, this procedure returns NOTATAG.             */
/*                                                                           */
/*  Note that when an object is freed, its first word or so gets             */
/*  overwritten by internal data, so it's a little bit dangerous to use this */
/*  procedure.  The caller needs to have a way to distinguish objects that   */
/*  it has previously freed, that does not rely on the first word of the     */
/*  object.  Yes, this is kludgy; but it would be slow for this procedure to */
/*  figure out whether an object has been freed or not, so speed was chosen  */
/*  over elegance.                                                           */
/*                                                                           */
/*  pool:  The proxipool whose tags you wish to iterate over.                */
/*  thistag:  The tag whose successor you seek, or NOTATAG to get started.   */
/*                                                                           */
/*  Returns the smallest allocated tag greater than `thistag', or NOTATAG if */
/*    there is no greater allocated tag.                                     */
/*                                                                           */
/*****************************************************************************/

tag proxipooliterate(struct proxipool *pool,
                     tag thistag)
{
  struct minipoolheader *mini;

  if (thistag == NOTATAG) {
    thistag = 0;
  } else {
    thistag++;
  }

  while (1) {
    if (thistag >= pool->nextgroup) {
      return NOTATAG;
    }
    mini = (struct minipoolheader *)
      arraypoollookup(&pool->minipoolarray, thistag >> LOG2OBJECTSPERMINI);
    /* Does a minipool containing tag `thistag' exist? */
    if (mini == (struct minipoolheader *) NULL) {
      /* No.  Jump to the start of the next group. */
      thistag = (thistag & (tag) ~(OBJECTSPERMINI * MINISPERGROUP - 1)) +
                OBJECTSPERMINI * MINISPERGROUP;
    } else if ((thistag & (OBJECTSPERMINI - 1)) >= mini->firstvirgin) {
      /* `thistag' has never been allocated.  Jump to the start of the */
      /*   next minipool.                                              */
      thistag = (thistag & (tag) ~(OBJECTSPERMINI - 1)) + OBJECTSPERMINI;
    } else {
      return thistag;
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  proxipoolinitpoolpools()   Initializes uninitialized poolpools.          */
/*                                                                           */
/*  The allocation map is an array of poolpools.  This procedure's job is to */
/*  initialize intervals of poolpools just before they are used.  This       */
/*  includes making sure the arraypool has allocated space for them.         */
/*                                                                           */
/*  pool:  The proxipool whose allocation map might need initializing.       */
/*  endindex:  Make sure all poolpools up to and including the one whose     */
/*    index is `endindex' are allocated and initialized.                     */
/*                                                                           */
/*****************************************************************************/

void proxipoolinitpoolpools(struct proxipool *pool,
                            proxipoolulong endindex)
{
  struct poolpool *poollist;

  /* Walk through the poolpools that have not been initialized yet, up to */
  /*   `endindex'.                                                        */
  while (pool->nextinitindex <= endindex) {
    /* Make sure memory has been allocated for this poolpool, and get */
    /*   a pointer to it.                                             */
    poollist = (struct poolpool *)
               arraypoolforcelookup(&pool->poolpools,
                                    (arraypoolulong) pool->nextinitindex);
    /* The linked lists of minipools and the groups are empty. */
    poollist->freelisthead = NOTATAG;
    poollist->freelisttail = NOTATAG;
    poollist->mygroup = NOTATAG;

    pool->nextinitindex++;
  }
}

/*****************************************************************************/
/*                                                                           */
/*  proxipoolnew()   Allocate space for an object in a proxipool.            */
/*                                                                           */
/*  An allocation index `allocindex' is used to place the new object close   */
/*  in memory to other objects with the same allocation index.               */
/*                                                                           */
/*  pool:  The proxipool to allocate an object from.                         */
/*  allocindex:  An allocation index associated with the object to ensure    */
/*    it is allocated in memory near other objects that are geometrically    */
/*    nearby.                                                                */
/*  outobject:  If `outobject' is not NULL, a pointer to the new object is   */
/*    returned at the location `outobject' points to.                        */
/*                                                                           */
/*  Returns the tag of the new object.                                       */
/*                                                                           */
/*****************************************************************************/

tag proxipoolnew(struct proxipool *pool,
                 proxipoolulong allocindex,
                 void **outobject)
{
  struct minipoolheader *allocmini;
  struct poolpool *poollist;
  void *objectptr;
  tag alloctag, nexttag;
  miniindex objectindex;

  /* If the poolpool at index `allocindex' has not been initialized yet, */
  /*   initialize all the unitialized poolpools up to `allocindex'.      */
  if (allocindex >= pool->nextinitindex) {
    proxipoolinitpoolpools(pool, allocindex);
  }

  /* Find the assigned poolpool. */
  poollist = (struct poolpool *) arraypoolfastlookup(&pool->poolpools,
                                                     allocindex);
  /* Find the first minipool in the poolpool's list. */
  alloctag = poollist->freelisthead;
  if (alloctag != NOTATAG) {
    /* Get a pointer to the minipool. */
    allocmini = proxipooltag2mini(pool, alloctag);
  } else {
    /* The poolpool's list of minipools is empty.  Check for an unfinished */
    /*   group to allocate a new minipool from.                            */
    alloctag = poollist->mygroup;
    if (alloctag == NOTATAG) {
      /* The poolpool has no group.  Assign a new minipool (and a new group) */
      /*   to this poolpool.                                                 */
      alloctag = pool->nextgroup;
      /* Allocate a different group next time. */
      pool->nextgroup += OBJECTSPERMINI * MINISPERGROUP;
    }

    /* Allocate a new minipool that starts with the tag `alloctag'. */
    allocmini = (struct minipoolheader *)
      arraypoolforcelookup(&pool->minipoolarray,
                           (arraypoolulong) (alloctag >> LOG2OBJECTSPERMINI));

    /* Reset the new minipool to a pristine state. */
    proxipoolrestartmini(pool, allocmini);
    /* Put the new minipool on the poolpool's list of minipools. */
    poollist->freelisthead = alloctag;
    poollist->freelisttail = alloctag;

    /* Inform the minipool of the index of its poolpool. */
    allocmini->allocindex = allocindex;

    /* Is there another minipool in the same group, and if so, is the next */
    /*   minipool unallocated?                                             */
    if ((((alloctag >> LOG2OBJECTSPERMINI) & (MINISPERGROUP - 1)) <
         MINISPERGROUP - 1) &&
        (arraypoollookup(&pool->minipoolarray,
                         (arraypoolulong)
                         (alloctag >> LOG2OBJECTSPERMINI) + 1) ==
         (void *) NULL)) {
      /* Remember this group and the next minipool for use in the future. */
      poollist->mygroup = alloctag + OBJECTSPERMINI;
    } else {
      poollist->mygroup = NOTATAG;
    }
  }

  /* Check if the linked list of dead objects is empty. */
  objectindex = allocmini->freestack;
  if (objectindex != NOTAMINIINDEX) {
    /* Allocate an object from the linked list, rather than a fresh one. */
    objectptr = (void *) 
                &allocmini->object1block[pool->objectbytes1 * objectindex];
    allocmini->freestack = * (miniindex *) objectptr;
  } else {
    /* Allocate a previously unused object. */
    objectindex = allocmini->firstvirgin;
    allocmini->firstvirgin++;
    objectptr = (void *)
                &allocmini->object1block[pool->objectbytes1 * objectindex];
  }

  /* The tag of the new object is its minipool prefix plus its index. */
  alloctag += objectindex;
  /* Is the minipool full? */
  if ((allocmini->freestack == NOTAMINIINDEX) &&
      (allocmini->firstvirgin >= (miniindex) OBJECTSPERMINI)) {
    /* The minipool is full.  Remove it from the linked list. */
    nexttag = allocmini->nextminifree;
    poollist->freelisthead = nexttag;
    if (nexttag == NOTATAG) {
      poollist->freelisttail = NOTATAG;
    }
  }

  pool->objects++;
  if (pool->objects > pool->maxobjects) {
    pool->maxobjects = pool->objects;
  }

  /* Return the new object's memory address (if desired) and tag. */
  if (outobject != (void **) NULL) {
    *outobject = objectptr;
  }
  return alloctag;
}

/*****************************************************************************/
/*                                                                           */
/*  proxipoolfree()   Deallocate an object, freeing its space for reuse.     */
/*                                                                           */
/*  WARNING:  Calling this procedure with a tag that is already free will    */
/*  probably corrupt the proxipool and cause the freed tag to be allocated   */
/*  more than once.                                                          */
/*                                                                           */
/*  pool:  The proxipool the object was allocated from.                      */
/*  killtag:  The tag of the object that is no longer in use.                */
/*                                                                           */
/*****************************************************************************/

void proxipoolfree(struct proxipool *pool,
                   tag killtag)
{
  struct minipoolheader *deallocmini;
  struct minipoolheader *tailmini;
  struct poolpool *poollist;
  miniindex objectindex;

  /* Get a pointer to the minipool. */
  deallocmini = proxipooltag2mini(pool, killtag);
  objectindex = (miniindex) (killtag & (tag) (OBJECTSPERMINI - 1));

  /* Is the minipool full? */
  if ((deallocmini->freestack == NOTAMINIINDEX) &&
      (deallocmini->firstvirgin >= (miniindex) OBJECTSPERMINI)) {
    /* The minipool will no longer be full, so put it back in its poolpool's */
    /*   linked list of minipools.                                           */
    poollist = (struct poolpool *)
               arraypoolfastlookup(&pool->poolpools, deallocmini->allocindex);
    killtag = killtag & ~ (tag) (OBJECTSPERMINI - 1);
    if (poollist->freelisthead == NOTATAG) {
      /* The list is empty; insert the minipool at the head of the list. */
      poollist->freelisthead = killtag;
    } else {
      /* Insert the minipool at the tail of the list. */
      tailmini = proxipooltag2mini(pool, poollist->freelisttail);
      tailmini->nextminifree = killtag;
    }
    poollist->freelisttail = killtag;
    /* There is no next minipool in the list. */
    deallocmini->nextminifree = NOTATAG;
  }

  /* Insert the object into the linked list of dead objects. */
  * (miniindex *)
    &deallocmini->object1block[pool->objectbytes1 * objectindex] =
      deallocmini->freestack;
  deallocmini->freestack = objectindex;

  pool->objects--;
}

/*****************************************************************************/
/*                                                                           */
/*  proxipoolobjects()   Returns the number of objects allocated in the      */
/*                       proximity-based memory pool.                        */
/*                                                                           */
/*  pool:  The proxipool in question.                                        */
/*                                                                           */
/*  Returns the number of objects currently allocated in `pool'.             */
/*                                                                           */
/*****************************************************************************/

arraypoolulong proxipoolobjects(struct proxipool *pool)
{
  return pool->objects;
}

/*****************************************************************************/
/*                                                                           */
/*  proxipoolbytes()   Returns the number of bytes of dynamic memory used by */
/*                     the proximity-based memory pool.                      */
/*                                                                           */
/*  Does not include the memory for the `struct proxipool' record itself.    */
/*                                                                           */
/*  pool:  The proxipool in question.                                        */
/*                                                                           */
/*  Returns the number of dynamically allocated bytes in `pool'.             */
/*                                                                           */
/*****************************************************************************/

arraypoolulong proxipoolbytes(struct proxipool *pool)
{
  return arraypoolbytes(&pool->minipoolarray) +
         arraypoolbytes(&pool->poolpools);
}

/**                                                                         **/
/**                                                                         **/
/********* Proximity-based memory pool management routines end here  *********/


/********* Z-order computation routines begin here                   *********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  zorderbefore()   Returns 1 if the point (x1, y1, z1) occurs before       */
/*                   (x2, y2, z2) in a z-order space-filling curve;          */
/*                   0 otherwise.  Coordinates are floating point.           */
/*                                                                           */
/*  I won't try to explain what a z-order curve is here; look it up on the   */
/*  Web.  This is a somewhat nonstandard z-order curve.  At the top level,   */
/*  points in different orthants are ordered as follows:                     */
/*                                                                           */
/*  nonnegative x, nonnegative y, negative z                                 */
/*  negative x, nonnegative y, negative z                                    */
/*  negative x, negative y, negative z                                       */
/*  nonnegative x, negative y, negative z                                    */
/*  nonnegative x, negative y, nonnegative z                                 */
/*  negative x, negative y, nonnegative z                                    */
/*  negative x, nonnegative y, nonnegative z                                 */
/*  nonnegative x, nonnegative y, nonnegative z (the positive orthant)       */
/*                                                                           */
/*  This is a one-level Hilbert curve.  Note that a zero coordinate is       */
/*  treated as a positive coordinate.  For example, (-1, 1, 1) precedes      */
/*  (0, 0, 1) in the ordering, because the latter point is treated as being  */
/*  in the positive orthant.                                                 */
/*                                                                           */
/*  In the positive orthant, this z-order curve progresses by decreasing z,  */
/*  then decreasing y, then increasing x.  For example, (0, 1, 1) precedes   */
/*  (1, 1, 1) precedes (0, 0, 1) precedes (1, 0, 1) precedes (0, 1, 0)       */
/*  precedes (1, 1, 0) precedes (0, 0, 0) precedes (1, 0, 0).  This ordering */
/*  is chosen to maximize the spatial locality of points in adjoining        */
/*  orthants.                                                                */
/*                                                                           */
/*  In the other orthants, the z-order curve is a reflection across one or   */
/*  more coordinate axes of the z-order curve in the positive orthant.  If   */
/*  the number of reflections is odd (i.e. for points with an odd number of  */
/*  negative coordinates), the z-order is also reversed; for example,        */
/*  (2, 3, 3) precedes (3, 3, 3), but (-3, 3, 3) precedes (-2, 3, 3).  This  */
/*  causes the z-ordering to adjoin nicely between orthants.                 */
/*                                                                           */
/*  This procedure requires IEEE 754 conformant floating-point double        */
/*  precision numbers.  It uses bit manipulation to extract exponents from   */
/*  floating-point numbers and to create numbers with specified exponents.   */
/*  It also uses the clever trick of exclusive-oring two significands to     */
/*  help figure out the first bit of disagreement between two floating-point */
/*  numbers with the same exponent.  Unfortunately, it needs to know the     */
/*  endianness of the hardware to work correctly.                            */
/*                                                                           */
/*  WARNING:  This routine does not work with denormalized numbers.          */
/*  I should fix that some time.                                             */
/*                                                                           */
/*  x1, y1, z1:  Coordinates of the first point to compare.                  */
/*  x2, y2, z2:  Coordinates of the second point to compare.                 */
/*                                                                           */
/*  Returns 1 if first point precedes the second in z-order; 0 otherwise.    */
/*                                                                           */
/*****************************************************************************/

int zorderbefore(starreal x1,
                 starreal y1,
                 starreal z1,
                 starreal x2,
                 starreal y2,
                 starreal z2)
{
  starreal xor, powerof2;
  long x1exp, x2exp, y1exp, y2exp, z1exp, z2exp;
  long xmax, ymax, zmax;
  int toggle;
  int endianness;

  /* For two points in the same orthant, toggle the result once for each */
  /*   negative coordinate in one of the points.                         */
  toggle = 0;
  /* The endianness of the hardware. */
  endianness = 1;

  /* Figure out which orthants the points are in. */
  if (z1 < 0.0) {
    if (z2 < 0.0) {
      /* Both points have negative z-coordinates; reverse the z-ordering. */
      toggle = 1;
      /* Reflect to positive z-coordinates. */
      z1 = -z1;
      z2 = -z2;
    } else {
      /* Negative z always precedes nonnegative z. */
      return 1;
    }
  } else if (z2 < 0.0) {
    /* Nonnegative z never precedes negative z. */
    return 0;
  }

  if (y1 < 0.0) {
    if (y2 < 0.0) {
      /* Both points have negative y-coordinates; reverse the z-ordering. */
      toggle = toggle ^ 1;
      /* Reflect to positive y-coordinates. */
      y1 = -y1;
      y2 = -y2;
    } else {
      /* Negative y precedes nonnegative y (unless z is negative). */
      return 1 ^ toggle;
    }
  } else if (y2 < 0.0) {
    /* Nonnegative y does not precede negative y (unless z is negative). */
    return toggle;
  }

  if (x1 < 0.0) {
    if (x2 < 0.0) {
      /* Both points have negative x-coordinates; reverse the z-ordering. */
      toggle = toggle ^ 1;
      /* Reflect to positive x-coordinates. */
      x1 = -x1;
      x2 = -x2;
    } else {
      /* Negative x precedes nonnegative x (unless toggled). */
      return 1 ^ toggle;
    }
  } else if (x2 < 0.0) {
    /* Nonnegative x does not precede negative x (unless toggled). */
    return toggle;
  }

  /* Determine the exponents of the floating-point numbers.  Note that IEEE  */
  /*   floating-point numbers do not express their exponents in two's        */
  /*   complement; rather, the exponent bits range from 1 to 2046, which     */
  /*   represent exponents from -1022 to 1023.  (Exponent bits of 0          */
  /*   represent denormalized numbers, and 2047 represents infinity or NaN.) */
  if (z1 == z2) {
    /* Check for the case where the two points are equal. */
    if ((x1 == x2) && (y1 == y2)) {
      /* A point does not precede itself. */
      return 0;
    }
    /* The z-coordinates are equal, so the other coordinates will determine */
    /*   which point comes first.  Set the z-exponents so small that they   */
    /*   cannot dominate the other exponents.                               */
    z1exp = -1l;
    z2exp = -1l;
  } else {
    /* Get the z-exponents by masking out the right bits. */
    z1exp = ((long *) &z1)[endianness] & 0x7ff00000l;
    z2exp = ((long *) &z2)[endianness] & 0x7ff00000l;
  }

  if (y1 == y2) {
    /* The y-coordinates are equal, so the other coordinates will determine */
    /*   which point comes first.  Set the y-exponents so small that they   */
    /*   cannot dominate the other exponents.                               */
    y1exp = -1l;
    y2exp = -1l;
  } else {
    /* Get the y-exponents by masking out the right bits. */
    y1exp = ((long *) &y1)[endianness] & 0x7ff00000l;
    y2exp = ((long *) &y2)[endianness] & 0x7ff00000l;
  }

  if (x1 == x2) {
    /* The x-coordinates are equal, so the other coordinates will determine */
    /*   which point comes first.  Set the x-exponents so small that they   */
    /*   cannot dominate the other exponents.                               */
    x1exp = -1l;
    x2exp = -1l;
  } else {
    /* Get the x-exponents by masking out the right bits. */
    x1exp = ((long *) &x1)[endianness] & 0x7ff00000l;
    x2exp = ((long *) &x2)[endianness] & 0x7ff00000l;
  }

  /* Compute the maximum z-, y-, and x-exponents. */
  zmax = z1exp > z2exp ? z1exp : z2exp;
  ymax = y1exp > y2exp ? y1exp : y2exp;
  xmax = x1exp > x2exp ? x1exp : x2exp;

  /* Repeat the following until one pair exponents clearly dominates. */
  /*   This loop iterates at most four times.                         */
  while (1) {
    if ((zmax >= ymax) && (zmax >= xmax)) {
      /* The largest z-exponent dominates, or at least equals, the x- and */
      /*   y-exponents.  Figure out if the z-exponents differ.            */
      if (z1exp < z2exp) {
        /* The z-exponent of the second point dominates, so (in the positive */
        /*   orthant) the second point precedes the first.                   */
        return toggle;
      } else if (z1exp > z2exp) {
        /* The z-exponent of the first point dominates, so (in the positive */
        /*   orthant) the first point precedes the second.                  */
        return 1 ^ toggle;
      } else {                                             /* z1exp == z2exp */
        /* Both points have the same z-exponent, so we need to determine  */
        /*   which bit of the two z-coordinates is the first to differ.   */
        /*   First, set `powerof2' to be 2^`z1exp', so `powerof2' has the */
        /*   same exponent as z1 and z2.                                  */
        ((long *) &powerof2)[!endianness] = 0l;
        ((long *) &powerof2)[endianness] = z1exp & 0x7ff00000l;
        /* Second, set `xor' to be a floating-point number whose exponent is */
        /*   `z1exp', and whose significand is the exclusive or of the       */
        /*   significands of z1 and z2--except the first bit of the          */
        /*   significand, which is the "hidden bit" of the IEEE format and   */
        /*   remains a 1.                                                    */
        ((long *) &xor)[!endianness] = ((long *) &z1)[!endianness] ^
                                       ((long *) &z2)[!endianness];
        ((long *) &xor)[endianness] = ((((long *) &z1)[endianness] ^
                                        ((long *) &z2)[endianness]) &
                                       ~0xfff00000l) | (z1exp & 0x7ff00000l);
        /* Third, subtract `powerof2' from `xor'.  Since they are both   */
        /*   positive and both have the same exponent, this operation is */
        /*   exact (no roundoff error), and the exponent of the result   */
        /*   will indicate the first bit where z1 and z2 disagree.       */
        xor -= powerof2;
        /* Determine the exponent of `xor'. */
        zmax = ((long *) &xor)[endianness] & 0x7ff00000l;
        /* If we were to cancel out the leading 1 bits of z1 and z2 that  */
        /*   agree, the larger of the two resulting numbers would have an */
        /*   exponent of `zmax'.  The exponent of the smaller one is      */
        /*   irrelevant, so set it really really small.                   */
        if (z1 > z2) {
          z1exp = zmax;
          z2exp = -1l;
        } else {
          z2exp = zmax;
          z1exp = -1l;
        }
        /* Now go through the loop again, because the z-exponent might */
        /*   or might not still dominate.                              */
      }
    } else if ((ymax > zmax) && (ymax >= xmax)) {
      /* The largest y-exponent dominates the z-exponents, and at least   */
      /*   equals the x-exponents.  Figure out if the y-exponents differ. */
      if (y1exp < y2exp) {
        /* The y-exponent of the second point dominates, so (in the positive */
        /*   orthant) the second point precedes the first.                   */
        return toggle;
      } else if (y1exp > y2exp) {
        /* The y-exponent of the first point dominates, so (in the positive */
        /*   orthant) the first point precedes the second.                  */
        return 1 ^ toggle;
      } else {
        /* Both points have the same y-exponent, so we need to determine  */
        /*   which bit of the two y-coordinates is the first to differ.   */
        /*   First, set `powerof2' to be 2^`y1exp', so `powerof2' has the */
        /*   same exponent as y1 and y2.                                  */
        ((long *) &powerof2)[!endianness] = 0l;
        ((long *) &powerof2)[endianness] = y1exp & 0x7ff00000l;
        /* Second, set `xor' to be a floating-point number whose exponent is */
        /*   `y1exp', and whose significand is the exclusive or of the       */
        /*   significands of y1 and y2--except the first bit of the          */
        /*   significand, which is the "hidden bit" of the IEEE format and   */
        /*   remains a 1.                                                    */
        ((long *) &xor)[!endianness] = ((long *) &y1)[!endianness] ^
                                       ((long *) &y2)[!endianness];
        ((long *) &xor)[endianness] = ((((long *) &y1)[endianness] ^
                                        ((long *) &y2)[endianness]) &
                                       ~0xfff00000l) | (y1exp & 0x7ff00000l);
        /* Third, subtract `powerof2' from `xor'.  Since they are both   */
        /*   positive and both have the same exponent, this operation is */
        /*   exact (no roundoff error), and the exponent of the result   */
        /*   will indicate the first bit where y1 and y2 disagree.       */
        xor -= powerof2;
        /* Determine the exponent of `xor'. */
        ymax = ((long *) &xor)[endianness] & 0x7ff00000l;
        /* If we were to cancel out the leading 1 bits of y1 and y2 that  */
        /*   agree, the larger of the two resulting numbers would have an */
        /*   exponent of `ymax'.  The exponent of the smaller one is      */
        /*   irrelevant, so set it really really small.                   */
        if (y1 > y2) {
          y1exp = ymax;
          y2exp = -1l;
        } else {
          y2exp = ymax;
          y1exp = -1l;
        }
        /* Now go through the loop again, because the y-exponent might */
        /*   or might not still dominate.                              */
      }
    } else {                               /* (xmax > ymax) && (xmax > zmax) */
      /* The largest x-exponent dominates the y- and z-exponents.  Figure */
      /*   out if the x-exponents differ.                                 */
      if (x1exp < x2exp) {
        /* The x-exponent of the second point dominates, so (in the positive */
        /*   orthant) the first point precedes the second.                   */
        return 1 ^ toggle;
      } else if (x1exp > x2exp) {
        /* The x-exponent of the first point dominates, so (in the positive */
        /*   orthant) the second point precedes the first.                  */
        return toggle;
      } else {
        /* Both points have the same x-exponent, so we need to determine  */
        /*   which bit of the two x-coordinates is the first to differ.   */
        /*   First, set `powerof2' to be 2^`x1exp', so `powerof2' has the */
        /*   same exponent as x1 and x2.                                  */
        ((long *) &powerof2)[!endianness] = 0l;
        ((long *) &powerof2)[endianness] = x1exp & 0x7ff00000l;
        /* Second, set `xor' to be a floating-point number whose exponent is */
        /*   `x1exp', and whose significand is the exclusive or of the       */
        /*   significands of x1 and x2--except the first bit of the          */
        /*   significand, which is the "hidden bit" of the IEEE format and   */
        /*   remains a 1.                                                    */
        ((long *) &xor)[!endianness] = ((long *) &x1)[!endianness] ^
                                       ((long *) &x2)[!endianness];
        ((long *) &xor)[endianness] = ((((long *) &x1)[endianness] ^
                                        ((long *) &x2)[endianness]) &
                                       ~0xfff00000l) | (x1exp & 0x7ff00000l);
        /* Third, subtract `powerof2' from `xor'.  Since they are both   */
        /*   positive and both have the same exponent, this operation is */
        /*   exact (no roundoff error), and the exponent of the result   */
        /*   will indicate the first bit where x1 and x2 disagree.       */
        xor -= powerof2;
        /* Determine the exponent of `xor'. */
        xmax = ((long *) &xor)[endianness] & 0x7ff00000l;
        /* If we were to cancel out the leading 1 bits of x1 and x2 that  */
        /*   agree, the larger of the two resulting numbers would have an */
        /*   exponent of `xmax'.  The exponent of the smaller one is      */
        /*   irrelevant, so set it really really small.                   */
        if (x1 > x2) {
          x1exp = xmax;
          x2exp = -1l;
        } else {
          x2exp = xmax;
          x1exp = -1l;
        }
        /* Now go through the loop again, because the x-exponent might */
        /*   or might not still dominate.                              */
      }
    }
  }
}

/**                                                                         **/
/**                                                                         **/
/********* Z-order computation routines end here                     *********/


/********* Allocation map routines begin here                        *********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  Allocation maps (struct allocmap)                                        */
/*                                                                           */
/*  An allocation map is a data structure that maps each point in 3D space   */
/*  to an "allocation index" (of type proxipoolulong), which determines      */
/*  which pool of memory data should be used to allocate structures          */
/*  associated with the point.  The allocation indices are meant for use     */
/*  with proxipools (proximity-based memory pools), though other data        */
/*  structures could be designed to use them as well.                        */
/*                                                                           */
/*  An allocation map allows a client to insert or delete "sample points."   */
/*  Each sample point is assigned a unique allocation index.  A client can   */
/*  query the allocation map with a point (not usually a sample point), and  */
/*  learn the allocation index of a sample point that is "near" the query    */
/*  point.  The purpose is to allow a client to store data structures so     */
/*  they are spatially coherent:  structures that are near each other        */
/*  geometrically also tend to be near each other in memory (because they    */
/*  are likely to have the same allocation index).                           */
/*                                                                           */
/*  A good way to use an allocation map is to have it contain points that    */
/*  are a small random sample of the entire point set processed by the       */
/*  client.  The random sample ensures that the points in the allocation map */
/*  are roughly representative of the spatial distribution of the larger     */
/*  point set.  The sample size should be chosen so perhaps thousands or     */
/*  tens of thousands of point map to a single allocation index.             */
/*                                                                           */
/*  Ideally, an allocation map would always return the allocation index of   */
/*  the sample point nearest the query point, perhaps using a dynamic        */
/*  Voronoi diagram.  But not only would that be a hassle to implement; it   */
/*  would be slower than I'd like.  Instead, I order the points along a      */
/*  space-filling z-order curve and store them in a splay tree.  The space-  */
/*  filling curve reduces the search problem to one dimension, so a simple   */
/*  data structure suffices; and splay trees run like greased weasels.  The  */
/*  region of space that maps to a sample point isn't ideally shaped, but    */
/*  it's good enough.                                                        */
/*                                                                           */
/*  A sample point can be removed from the allocation map.  Part of the      */
/*  reason for this is to support dynamically changing triangulations, in    */
/*  which vertices might just disappear.  When a sample point is removed,    */
/*  its allocation index is placed in a "spare tree," from which it can be   */
/*  reallocated again.  The goal is to make sure that the memory pools (say, */
/*  in a proxipool) associated with an allocation index don't fall into      */
/*  disuse (which would be bad, as they're still taking up memory.  When a   */
/*  sample point is inserted into the allocation tree, the code finds the    */
/*  allocation index in the spare tree whose old sample point is closest to  */
/*  the new sample point, and allocates that index to the new point.  With   */
/*  luck, the new points that map to the index might partly overlap the old  */
/*  points, still in use, that used to map to the index.  When the spare     */
/*  tree is empty, the code allocates brand spankin' new indices.            */
/*                                                                           */
/*  If there are no sample points in the allocation map, every point maps to */
/*  a default allocation index of zero.  When sample points do exist, their  */
/*  allocation indices are numbered starting from one--no sample point ever  */
/*  get assigned the allocation index zero.                                  */
/*                                                                           */
/*  Public interface:                                                        */
/*  struct allocmap   Allocation map object.                                 */
/*  void allocmapinit(tree, verbose)   Initialize an empty allocation tree.  */
/*  void allocmaprestart(tree)   Deallocates all the tree nodes (not to OS). */
/*  void allocmapdeinit()   Free an allocation tree's memory to the OS.      */
/*  proxipoolulong allocmapindex(tree, x, y, z)   Query a point, returning   */
/*    an allocation index.                                                   */
/*  proxipoolulong allocmapnewpoint(tree, x, y, z)   Insert a point.         */
/*  void allocmapdeletepoint(tree, x, y, z)   Delete a point.                */
/*  arraypoolulong allocmapbytes(tree)   Returns memory taken by tree.       */
/*                                                                           */
/*  For internal use only:                                                   */
/*  struct allocmapnode *allocmapnewnode(tree)                               */
/*  int allocmapsplay(treeroot, x, y, z, nearnode)                           */
/*  void allocmapmax(treeroot)                                               */
/*  void allocmapinsertroot(treeroot, insertnode, splayside)                 */
/*  void allocmapremoveroot(treeroot)                                        */
/*                                                                           */
/*****************************************************************************/


/*  The logarithm of the number of allocation tree nodes allocated at once.  */

#define LOG2OCTREENODESPERBLOCK 8


/*  Each `allocmapnode' is a node in the allocation tree.  Its fields        */
/*  include its `left' and `right' children and its sample point             */
/*  (xsam, ysam, zsam).  Each node has an allocation index `index', which is */
/*  the node's index in the arraypool of nodes, and is also used by          */
/*  memorypools to decide which chunks of memory to allocate objects from.   */
/*                                                                           */
/*  The node with index zero is the "default" node.  This node can never be  */
/*  part of the splay tree.  It is the node returned when the splay tree is  */
/*  empty, so that every point can be assigned an allocation index even when */
/*  there are no points in the tree.  Nodes allocated to participate in the  */
/*  tree are numbered starting from one.                                     */

struct allocmapnode {
  struct allocmapnode *left, *right;          /* My left and right children. */
  starreal xsam, ysam, zsam;     /* Coordinates of this node's sample point. */
  proxipoolulong index;                      /* My index (in the arraypool). */
};

/*  Each `allocmap' is an allocation tree, used to map a point in 3D space   */
/*  to an index that specifies which minipool (in a proxipool) an object     */
/*  should be allocated from.  The idea is that points that are spatially    */
/*  close together should be close together in memory too.  The allocation   */
/*  tree data structure is a splay tree whose points are ordered along a     */
/*  z-order space-filling curve.                                             */
/*                                                                           */
/*  The nodes are allocated from the memory pool `nodearray'.  The root of   */
/*  the allocation tree is `allocroot'.  When a node is removed from the     */
/*  allocation tree, it is inserted into the spare tree, whose root is       */
/*  `spareroot'.  Nodes in the spare tree can be reused, whereupon they are  */
/*  inserted back into the allocation tree.  The purpose of the spare tree   */
/*  is to allow reuse of allocation indices in a spatially coherent way--    */
/*  ideally, a new point in the allocation tree will receive an index that   */
/*  was previously used by a point close to it.                              */
/*                                                                           */
/*  The number "verbosity" indicates how much debugging information to       */
/*  print, from none (0) to lots (4+).                                       */

struct allocmap {
  struct arraypool nodearray;      /* Tiered array of allocation tree nodes. */
  struct allocmapnode *allocroot;                /* Root of allocation tree. */
  struct allocmapnode *spareroot;                /* Root of spare node tree. */
  int verbosity;                /* Amount of debugging information to print. */
};


/*****************************************************************************/
/*                                                                           */
/*  allocmaprestart()   Deallocate all the tree nodes in an allocmap.        */
/*                                                                           */
/*  The tree returns to its starting state, except that no memory (allocated */
/*  by the arraypool of tree nodes) is freed to the operating system.        */
/*                                                                           */
/*  tree:  The allocmap to restart.                                          */
/*                                                                           */
/*****************************************************************************/

void allocmaprestart(struct allocmap *tree)
{
  struct allocmapnode *defaultnode;
  arraypoolulong defaultindex;

  /* Empty the trees. */
  tree->allocroot = (struct allocmapnode *) NULL;
  tree->spareroot = (struct allocmapnode *) NULL;

  /* Restart the pool of tree nodes. */
  arraypoolrestart(&tree->nodearray);

  /* Allocate a "default" node (which is never in either tree) having index */
  /*   zero.                                                                */
  defaultindex = arraypoolnewindex(&tree->nodearray, (void **) &defaultnode);
  if (defaultindex != 0) {
    printf("Internal error in allocmaprestart():\n");
    printf("  First index allocated from restarted arraypool is not zero.\n");
    internalerror();
  }

  defaultnode->index = 0;
  /* Give the default node a bogus sample point. */
  defaultnode->xsam = 0.0;
  defaultnode->ysam = 0.0;
  defaultnode->zsam = 0.0;
}

/*****************************************************************************/
/*                                                                           */
/*  allocmapinit()   Initialize an empty allocation tree.                    */
/*                                                                           */
/*  tree:  The allocmap to initialize.                                       */
/*  verbose:  How much debugging information allocmap procedures should      */
/*    print, from none (0) to lots (4+).                                     */
/*                                                                           */
/*****************************************************************************/

void allocmapinit(struct allocmap *tree,
                  int verbose)
{
  /* Initialize an arraypool to allocate nodes from.  Note that this is an */
  /*   array of actual nodes, not an array of pointers to nodes.           */
  arraypoolinit(&tree->nodearray,
                (arraypoolulong) sizeof(struct allocmapnode),
                (arraypoolulong) LOG2OCTREENODESPERBLOCK, 1);
  tree->verbosity = verbose;
  /* Empty out the tree and set up the default node. */
  allocmaprestart(tree);
}

/*****************************************************************************/
/*                                                                           */
/*  allocmapdeinit()   Free to the operating system all memory taken by an   */
/*                     allocation tree.                                      */
/*                                                                           */
/*  tree:  The allocmap to free.                                             */
/*                                                                           */
/*****************************************************************************/

void allocmapdeinit(struct allocmap *tree)
{
  arraypooldeinit(&tree->nodearray);
}

/*****************************************************************************/
/*                                                                           */
/*  allocmapnewnode()   Allocate a new node in an allocation tree.           */
/*                                                                           */
/*  This routine may allocate a node that has been previously freed.  If so, */
/*  the node has the same index it had before.  (Node indices never change.) */
/*                                                                           */
/*  tree:  The allocmap to allocate a new node from.                         */
/*                                                                           */
/*  Returns a pointer to the new node.                                       */
/*                                                                           */
/*****************************************************************************/

struct allocmapnode *allocmapnewnode(struct allocmap *tree)
{
  struct allocmapnode *newnode;
  arraypoolulong newindex;

  /* Allocate a node from the arraypool. */
  newindex = arraypoolnewindex(&tree->nodearray, (void **) &newnode);
  /* Teach it its own index. */
  newnode->index = (proxipoolulong) newindex;

  return newnode;
}

/*****************************************************************************/
/*                                                                           */
/*  allocmapsplay()   This top-down splay tree code searches the tree for a  */
/*                    node with coordinates (x, y, z), and splays it (if it  */
/*                    is found) or the last node encountered to the root.    */
/*                    Nodes in the tree are ordered by a z-order space-      */
/*                    filling curve.                                         */
/*                                                                           */
/*  If the search does not find a node whose sample point is exactly         */
/*  (x, y, z), consider two nodes:  the latest node that precedes (x, y, z), */
/*  and the earliest node that follows (x, y, z).  One of these nodes,       */
/*  chosen arbitrarily, is splayed to the root (if the tree is not empty).   */
/*  If both nodes exist (i.e. (x, y, z) does not precede every node in the   */
/*  tree, nor follow every node), the other node is stored in `*nearnode' on */
/*  return.                                                                  */
/*                                                                           */
/*  If the search finds an exact match, or if (x, y, z) precedes or follows  */
/*  every node in the tree, then `*nearnode' is NULL on return.              */
/*                                                                           */
/*  treeroot:  The root of the tree in which to search, twice indirected.    */
/*    On return, `*treeroot' will point to the new root.                     */
/*  x, y, z:  The coordinates of the point whose near neighbor is sought.    */
/*  nearnode:  On return, `*nearnode' may point to a node containing an      */
/*    alternative point near (x, y, z).  Output only; the value of           */
/*    `*nearnode' on entry is irrelevant.                                    */
/*                                                                           */
/*  Returns 0 if a node with value (x, y, z) is found and splayed to the     */
/*    root; -1 if (x, y, z) precedes the node splayed to the root; or 1 if   */
/*    (x, y, z) follows the node splayed to the root.  Returns 0 if the tree */
/*    is empty.                                                              */
/*                                                                           */
/*****************************************************************************/

int allocmapsplay(struct allocmapnode **treeroot,
                  starreal x,
                  starreal y,
                  starreal z,
                  struct allocmapnode **nearnode)
{
  struct allocmapnode catcher;
  struct allocmapnode *root;
  struct allocmapnode *child;
  struct allocmapnode *leftcatcher, *rightcatcher;
  int compare;

  *nearnode = (struct allocmapnode *) NULL;

  root = *treeroot;
  if (root == (struct allocmapnode *) NULL) {
    /* The tree is empty. */
    return 0;
  }

  /* `catcher' is an allocmapnode which will not be part of the final tree,  */
  /*   but is used temporarily to hold subtrees.  The subtree that will be   */
  /*   the left child of the root is stored as the right child of `catcher', */
  /*   and vice versa.  (This backward connection simplifies the algorithm.) */
  /*   `leftcatcher' is a pointer used up to build up the left subtree of    */
  /*   the root, from top to bottom right; it points to the rightmost node   */
  /*   in the subtree.  `rightcatcher' serves a symmetric purpose.           */
  leftcatcher = &catcher;
  rightcatcher = &catcher;

  /* Loop of splaying operations.  During each iteration, `root' is the node */
  /*   currently being visited, as well as the root of the subtree currently */
  /*   being searched.                                                       */
  while (1) {
    /* Compare (x, y, z) with this node's sample point.  The result is */
    /*   0 if equal; -1 if (x, y, z) precedes; 1 if (x, y, z) follows. */
    compare = ((x == root->xsam) && (y == root->ysam) && (z == root->zsam)) ?
              0 : zorderbefore(x, y, z, root->xsam, root->ysam, root->zsam) ?
              -1 : 1;
    /* Is `root' the node that will be the root in the end? */
    if ((compare == 0) ||
        ((compare < 0) && (root->left == (struct allocmapnode *) NULL)) ||
        ((compare > 0) && (root->right == (struct allocmapnode *) NULL))) {
      /* Yes, the search is over.  If `root' has children, attach them to */
      /*   the new left and right subtrees.                               */
      leftcatcher->right = root->left;
      rightcatcher->left = root->right;
      /* Attach the left and right subtrees to the new root. */
      root->left = catcher.right;
      root->right = catcher.left;
      /* The new root is `root'. */
      *treeroot = root;
      /* Find the node `nearnode' such that (x, y, z) is between `root' */
      /*   and `nearnode'.                                              */
      if ((compare < 0) && (leftcatcher != &catcher)) {
        *nearnode = leftcatcher;
      } else if ((compare > 0) && (rightcatcher != &catcher)) {
        *nearnode = rightcatcher;
      }
      return compare;
    } else if (compare < 0) {
      /* Search the left subtree of `root'. */
      child = root->left;
      /* Compare (x, y, z) with the left child's sample point. */
      compare = ((x == child->xsam) && (y == child->ysam) &&
                 (z == child->zsam)) ? 0 :
                zorderbefore(x, y, z, child->xsam, child->ysam, child->zsam) ?
                -1 : 1;
      /* Is `child' the node that will be the root in the end? */
      if ((compare == 0) ||
          ((compare < 0) && (child->left == (struct allocmapnode *) NULL)) ||
          ((compare > 0) && (child->right == (struct allocmapnode *) NULL))) {
        /* Yes, the search is over.  Perform a "zig" rotation. */
        root->left = child->right;
        /* If `child' has a left child, attach it to the new left subtree. */
        /*   Attach `root' to the new right subtree.                       */
        leftcatcher->right = child->left;
        rightcatcher->left = root;
        /* Attach the left and right subtrees to the new root. */
        child->left = catcher.right;
        child->right = catcher.left;
        /* The new root is `child'. */
        *treeroot = child;
        /* Find the node such that (x, y, z) is between `child' and */
        /*   `nearnode'.                                            */
        if (compare > 0) {
          *nearnode = root;
        } else if ((compare < 0) && (leftcatcher != &catcher)) {
          *nearnode = leftcatcher;
        }
        return compare;
      } else if (compare < 0) {
        /* The search continues to the left.  Perform a "zig-zig" rotation. */
        root->left = child->right;
        child->right = root;
        /* Attach the child to the new right subtree. */
        rightcatcher->left = child;
        rightcatcher = child;
        /* On the next iteration, examine the left-left grandchild of */
        /*   `root'.                                                  */
        root = child->left;
      } else {
        /* The search continues to the right.  Perform a "zig-zag" rotation  */
        /*   by attaching the left child to the new left subtree, and `root' */
        /*   to the new right subtree.                                       */
        leftcatcher->right = child;
        leftcatcher = child;
        rightcatcher->left = root;
        rightcatcher = root;
        /* On the next iteration, examine the left-right grandchild of */
        /*   `root'.                                                   */
        root = child->right;
      }
    } else {
      /* Search the right subtree of `root'. */
      child = root->right;
      /* Compare (x, y, z) with the right child's sample point. */
      compare = ((x == child->xsam) && (y == child->ysam) &&
                 (z == child->zsam)) ? 0 :
                zorderbefore(x, y, z, child->xsam, child->ysam, child->zsam) ?
                -1 : 1;
      /* Is `child' the node that will be the root in the end? */
      if ((compare == 0) ||
          ((compare < 0) && (child->left == (struct allocmapnode *) NULL)) ||
          ((compare > 0) && (child->right == (struct allocmapnode *) NULL))) {
        /* Yes, the search is over.  Perform a "zig" rotation. */
        root->right = child->left;
        /* If `child' has a right child, attach it to the new right subtree. */
        /*   Attach `root' to the new left subtree.                          */
        leftcatcher->right = root;
        rightcatcher->left = child->right;
        /* Attach the left and right subtrees to the new root. */
        child->left = catcher.right;
        child->right = catcher.left;
        /* The new root is `child'. */
        *treeroot = child;
        /* Find the node `nearnode' such that (x, y, z) is between `child' */
        /*   and `nearnode'.                                               */
        if (compare < 0) {
          *nearnode = root;
        } else if ((compare > 0) && (rightcatcher != &catcher)) {
          *nearnode = rightcatcher;
        }
        return compare;
      } else if (compare > 0) {
        /* The search continues to the right.  Perform a "zig-zig" rotation. */
        root->right = child->left;
        child->left = root;
        /* Attach the child to the new left subtree. */
        leftcatcher->right = child;
        leftcatcher = child;
        /* On the next iteration, examine the right-right grandchild of */
        /*   `root'.                                                    */
        root = child->right;
      } else {
        /* The search continues to the left.  Perform a "zig-zag" rotation */
        /*   by attaching `root' to the new left subtree, and the right    */
        /*   child to the new left subtree.                                */
        leftcatcher->right = root;
        leftcatcher = root;
        rightcatcher->left = child;
        rightcatcher = child;
        /* On the next iteration, examine the right-left grandchild of */
        /*   `root'.                                                   */
        root = child->left;
      }
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  allocmapmax()   Splays the rightmost node of a tree to the root.         */
/*                                                                           */
/*  treeroot:  The root of the tree to splay, twice indirected.  On return,  */
/*    `*treeroot' will point to the new root.                                */
/*                                                                           */
/*****************************************************************************/

void allocmapmax(struct allocmapnode **treeroot)
{
  struct allocmapnode catcher;
  struct allocmapnode *root;
  struct allocmapnode *rightchild;
  struct allocmapnode *leftcatcher;

  root = *treeroot;
  if (root == (struct allocmapnode *) NULL) {
    /* The tree is empty. */
    return;
  }

  /* `catcher' is an allocmapnode which will not be part of the final tree,  */
  /*   but is used temporarily to hold a subtree.  The subtree that will be  */
  /*   the left child of the root is stored as the right child of `catcher'. */
  /*   (This backward connection simplifies the algorithm.)  `leftcatcher'   */
  /*   is a pointer used up to build up the left subtree of the root, from   */
  /*   top to bottom right; it points to the rightmost node in the subtree.  */
  leftcatcher = &catcher;

  /* Search to the far right of the tree, splaying as we go. */
  while (1) {
    rightchild = root->right;
    if (rightchild == (struct allocmapnode *) NULL) {
      /* If `root' has a left child, attach it to the new left subtree. */
      leftcatcher->right = root->left;
      /* Attach the left subtree to the new root. */
      root->left = catcher.right;
      /* The new root is `root'. */
      *treeroot = root;
      return;
    } else if (rightchild->right == (struct allocmapnode *) NULL) {
      /* The right child of `root' will be the new root.  Perform a "zig" */
      /*   rotation.                                                      */
      root->right = rightchild->left;
      /* Attach `root' to the bottom right of the new left subtree. */
      leftcatcher->right = root;
      /* Attach the left subtree to the new root. */
      rightchild->left = catcher.right;
      /* The new root is `rightchild'. */
      *treeroot = rightchild;
      return;
    } else {
      /* The search continues to the right.  Perform a "zig-zig" rotation. */
      root->right = rightchild->left;
      rightchild->left = root;
      /* Attach the child to the new left subtree. */
      leftcatcher->right = rightchild;
      leftcatcher = rightchild;
      /* On the next iteration, examine the right-right grandchild of */
      /*   `root'.                                                    */
      root = rightchild->right;
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  allocmapinsertroot()   Finish inserting a node into a splay tree.        */
/*                                                                           */
/*  After a splay tree is splayed with allocmapsplay() on the coordinates    */
/*  (x, y, z), this procedure is used to finish inserting a node with point  */
/*  (x, y, z) into the splay tree.  The new node becomes the root of the     */
/*  tree.                                                                    */
/*                                                                           */
/*  treeroot:  The root of the tree in which to insert the new node, twice   */
/*    indirected.  On return, `*treeroot' will point to the new root.        */
/*  insertnode:  The node to insert into the tree.                           */
/*  splayside:  The value returned by allocmapsplay().  -1 if (x, y, z)      */
/*    precedes the node splayed to the root; 1 if (x, y, z) follows the node */
/*    splayed to the root; irrelevant if the tree is empty or the node       */
/*    splayed to the root is also (x, y, z).                                 */
/*                                                                           */
/*****************************************************************************/

void allocmapinsertroot(struct allocmapnode **treeroot,
                        struct allocmapnode *insertnode,
                        int splayside)
{
  /* Is the tree empty? */
  if (*treeroot == (struct allocmapnode *) NULL) {
    /* Empty tree; the new node has no children. */
    insertnode->left = (struct allocmapnode *) NULL;
    insertnode->right = (struct allocmapnode *) NULL;
  } else if (splayside < 0) {
    /* The new sample point precedes the root's sample point.  The root   */
    /*   becomes the new node's right child, and the root's (former) left */
    /*   child becomes the new node's left child.                         */
    insertnode->left = (*treeroot)->left;
    insertnode->right = *treeroot;
    (*treeroot)->left = (struct allocmapnode *) NULL;
  } else {
    /* The new sample point follows the root's sample point.  The root    */
    /*   becomes the new node's left child, and the root's (former) right */
    /*   child becomes the new node's right child.                        */
    insertnode->left = *treeroot;
    insertnode->right = (*treeroot)->right;
    (*treeroot)->right = (struct allocmapnode *) NULL;
  }
  /* The new node becomes the root. */
  *treeroot = insertnode;
}

/*****************************************************************************/
/*                                                                           */
/*  allocmapremoveroot()   Removes the root from a splay tree.               */
/*                                                                           */
/*  Does nothing if the tree is empty.                                       */
/*                                                                           */
/*  treeroot:  The root of the tree in which to insert the new node, twice   */
/*    indirected.  On return, `*treeroot' will point to the new root.        */
/*                                                                           */
/*****************************************************************************/

void allocmapremoveroot(struct allocmapnode **treeroot)
{
  struct allocmapnode *root;
  struct allocmapnode *left;
  struct allocmapnode *right;

  /* Do nothing if the tree is empty. */
  if (*treeroot != (struct allocmapnode *) NULL) {
    /* Remove the root from the tree. */
    root = *treeroot;
    left = root->left;
    right = root->right;
    if (left == (struct allocmapnode *) NULL) {
      /* Root has no left child, so its right child becomes the new root. */
      *treeroot = right;
    } else {
      *treeroot = left;
      /* Did the old root have a right child? */
      if (right != (struct allocmapnode *) NULL) {
        /* The largest entry in the left subtree becomes the new root. */
        allocmapmax(treeroot);
        /* Attach the former right subtree. */
        (*treeroot)->right = right;
      }
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  allocmapindex()   Find the node in an allocation tree whose sample point */
/*                    is "closest" to (x, y, z), and return its index.       */
/*                                                                           */
/*  If the tree contains a node whose sample point is (x, y, z), then that   */
/*  node's index is returned.  Otherwise, returns the node whose sample      */
/*  point is immediately before or after (x, y, z) in the z-order.  If there */
/*  are two choices (the node immediately before vs. the node immediately    */
/*  after), selects the nearest one by Euclidean distance.                   */
/*                                                                           */
/*  tree:  The allocmap in which to search.                                  */
/*  x, y, z:  The coordinates of the point whose near neighbor is sought.    */
/*                                                                           */
/*  Returns the index of the found node.  If the tree is empty, returns      */
/*    zero, which acts as a default index.                                   */
/*                                                                           */
/*****************************************************************************/

proxipoolulong allocmapindex(struct allocmap *tree,
                             starreal x,
                             starreal y,
                             starreal z)
{
  struct allocmapnode *foundnode;
  struct allocmapnode *othernode;
  int splayside;

  /* If the tree is empty, the default index is zero. */
  if (tree->allocroot == (struct allocmapnode *) NULL) {
    return 0;
  }

  /* Search for (x, y, z) and splay some node to the top. */
  splayside = allocmapsplay(&tree->allocroot, x, y, z, &othernode);
  foundnode = tree->allocroot;

  if ((splayside != 0) && (othernode != (struct allocmapnode *) NULL)) {
    /* Decide which node--`foundnode' or `othernode'--is closest to */
    /*   (x, y, z) by Euclidean distance.                           */
    if ((x - othernode->xsam) * (x - othernode->xsam) +
        (y - othernode->ysam) * (y - othernode->ysam) +
        (z - othernode->zsam) * (z - othernode->zsam) <
        (x - foundnode->xsam) * (x - foundnode->xsam) +
        (y - foundnode->ysam) * (y - foundnode->ysam) +
        (z - foundnode->zsam) * (z - foundnode->zsam)) {
      return othernode->index;
    }
  }

  return foundnode->index;
}

/*****************************************************************************/
/*                                                                           */
/*  allocmapnewpoint()   Add a new sample point (x, y, z) to the allocation  */
/*                       tree.                                               */
/*                                                                           */
/*  If the point (x, y, z) is already in the tree, this procedure does not   */
/*  insert a new one.                                                        */
/*                                                                           */
/*  tree:  The allocmap in which to insert the new point.                    */
/*  x, y, z:  The coordinates of the sample point to insert.                 */
/*                                                                           */
/*  Returns the index of the new node, or the index of the preexisting node  */
/*    if (x, y, z) is already in the tree.                                   */
/*                                                                           */
/*****************************************************************************/

proxipoolulong allocmapnewpoint(struct allocmap *tree,
                                starreal x,
                                starreal y,
                                starreal z)
{
  struct allocmapnode *newnode;
  struct allocmapnode *othernode;
  int splayside = 0;

  /* If the tree is not empty, splay the tree to find a good spot to insert */
  /*   the new node.                                                        */
  if (tree->allocroot != (struct allocmapnode *) NULL) {
    splayside = allocmapsplay(&tree->allocroot, x, y, z, &othernode);
    if (splayside == 0) {
      /* The point is already in the tree. */
      return tree->allocroot->index;
    }
  }

  /* Allocate a node to hold the new sample point. */
  if (tree->spareroot == (struct allocmapnode *) NULL) {
    /* No freed nodes left.  Allocate a brand new one. */
    newnode = allocmapnewnode(tree);
  } else {
    /* Find a freed node whose sample point was near (x, y, z) and */
    /*   remove it from the spare tree.                            */
    splayside = allocmapsplay(&tree->spareroot, x, y, z, &othernode);
    newnode = tree->spareroot;
    if ((splayside != 0) && (othernode != (struct allocmapnode *) NULL)) {
      /* Decide which node--`newnode' or `othernode'--is closest to */
      /*   (x, y, z) by Euclidean distance.                         */
      if ((x - othernode->xsam) * (x - othernode->xsam) +
          (y - othernode->ysam) * (y - othernode->ysam) +
          (z - othernode->zsam) * (z - othernode->zsam) <
          (x - newnode->xsam) * (x - newnode->xsam) +
          (y - newnode->ysam) * (y - newnode->ysam) +
          (z - newnode->zsam) * (z - newnode->zsam)) {
        allocmapsplay(&tree->spareroot, othernode->xsam, othernode->ysam,
                      othernode->zsam, &othernode);
        newnode = tree->spareroot;
      }
    }

    allocmapremoveroot(&tree->spareroot);
  }
  newnode->xsam = x;
  newnode->ysam = y;
  newnode->zsam = z;

  /* The new node becomes the root of the allocation tree. */
  allocmapinsertroot(&tree->allocroot, newnode, splayside);

  return newnode->index;
}

/*****************************************************************************/
/*                                                                           */
/*  allocmapdeletepoint()   Deletes a sample point (x, y, z) from the        */
/*                          allocation tree.                                 */
/*                                                                           */
/*  Does nothing if the point (x, y, z) is not actually in the tree.         */
/*                                                                           */
/*  The allocation index associated with (x, y, z) is placed in a "spare     */
/*  tree," so it can be reused--hopefully associated with a new point that   */
/*  is close to (x, y, z).                                                   */
/*                                                                           */
/*  tree:  The allocmap from which to delete the point.                      */
/*  x, y, z:  The coordinates of the sample point to delete.                 */
/*                                                                           */
/*****************************************************************************/

void allocmapdeletepoint(struct allocmap *tree,
                         starreal x,
                         starreal y,
                         starreal z)
{
  struct allocmapnode *deletenode;
  struct allocmapnode *dummynode;
  int splayside;

  /* Do nothing if the tree is empty. */
  if (tree->allocroot != (struct allocmapnode *) NULL) {
    /* Try to splay the point (x, y, z) to the root. */
    splayside = allocmapsplay(&tree->allocroot, x, y, z, &dummynode);

    /* Do nothing if the node is not found. */
    if (splayside == 0) {
      /* Remember the deleted node. */
      deletenode = tree->allocroot;
      /* Remove it from the tree. */
      allocmapremoveroot(&tree->allocroot);

      /* If the spare tree is not empty, splay it to find a good spot to */
      /*   insert the deleted node.                                      */
      if (tree->spareroot != (struct allocmapnode *) NULL) {
        /* Find where to insert (x, y, z) in the spare tree. */
        splayside = allocmapsplay(&tree->spareroot, x, y, z, &dummynode);
      }
      /* The deleted node becomes the root of the spare tree, ready to be */
      /*   reused.                                                        */
      allocmapinsertroot(&tree->spareroot, deletenode, splayside);
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  allocmapbytes()   Returns the size (in bytes) of the allocation tree.    */
/*                                                                           */
/*  Returns the dynamically allocated memory used by the arraypool used to   */
/*  store the nodes of the tree.  Does not include the size of the `struct   */
/*  allocmap', which is presumably part of some other object and accounted   */
/*  for there.  Note that allocmaps only release memory to the operating     */
/*  system when allocmapdeinit() is called, and the return value includes    */
/*  the memory occupied by all the spare nodes.                              */
/*                                                                           */
/*  tree:  The allocmap in question.                                         */
/*                                                                           */
/*  Returns the number of dynamically allocated bytes in `tree'.             */
/*                                                                           */
/*****************************************************************************/

arraypoolulong allocmapbytes(struct allocmap *tree)
{
  return arraypoolbytes(&tree->nodearray);
}

/**                                                                         **/
/**                                                                         **/
/********* Allocation map routines end here                          *********/


/********* Link ring routines begin here                             *********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  Compressed link rings                                                    */
/*                                                                           */
/*  The link of a vertex in a 2D triangulation, and the link of an edge in   */
/*  a 3D triangulation, is a set of vertices and edges ordered circularly    */
/*  around the vertex/edge that defines the triangles/tetrahedra that        */
/*  include the vertex/edge.  I call these one-dimensional links "link       */
/*  rings", distinguishing them from higher-dimensional links like the link  */
/*  of a vertex in a 3D triangulation (which is a 2D triangulation).         */
/*                                                                           */
/*  Of course, a one-dimensional link is only truly a ring for a vertex/edge */
/*  in the interior of a triangulation.  A boundary vertex/edge has one or   */
/*  more gaps in its ring, so its link is comprised of one or more chains.   */
/*  I fill in the gaps with a "ghost vertex" whose sole job is to represent  */
/*  such gaps, so the link is always represented as a ring.                  */
/*                                                                           */
/*  Link rings should all be thought of as sharing a fixed "orientation".    */
/*  I use counterclockwise, but this code would never know if you reflected  */
/*  it.  In fact, this code is deliberately oblivious to geometry--it never  */
/*  looks at a coordinate.                                                   */
/*                                                                           */
/*  Link rings are stored in a compressed format adapted from Blandford,     */
/*  Blelloch, Cardoze, and Kadow.  See the header for a full citation.       */
/*                                                                           */
/*  Each link ring is stored in a linked list of list nodes of type          */
/*  `molecule'.  Molecules are allocated dynamically and constitute most of  */
/*  the memory occupied by a mesh.                                           */
/*                                                                           */
/*  Some invariants of link rings:                                           */
/*                                                                           */
/*  - Both vertices and link rings are represented by tags, which are        */
/*    defined as a part of the proxipool definitions.  (But vertices and     */
/*    links are allocated from different proxipools, so a vertex tag of 31   */
/*    and a link tag of 31 are unrelated to each other.)                     */
/*                                                                           */
/*  - A molecule is a short piece of memory.  Every molecule is the same     */
/*    length.  Every molecule has a tag (and is allocated from a proxipool). */
/*    Every link ring tag indexes the first molecule in the link ring.       */
/*                                                                           */
/*  - Molecules store compressed tags.  Each compressed tag is partitioned   */
/*    into 7-bit chunks called "atoms", ordered from most significant to     */
/*    least significant.  The high-order eighth bit of each atom is a "stop  */
/*    bit", set to one to signify the final atom of a compressed tag.        */
/*                                                                           */
/*  - Compressed tags vary in length.  The compression mechanism is simply   */
/*    to leave out the high-order atoms of the tag.  Some number of low-     */
/*    order atoms remain.  The number of atoms that remain depends on which  */
/*    atoms of the tag differ from the atoms of a "ground tag" used as the   */
/*    basis for compression.  Compressed vertex tags use a different ground  */
/*    tag than compressed molecule tags.                                     */
/*                                                                           */
/*  - The high-order bits of a compressed vertex are supplied by the ground  */
/*    tag, whose identity is fixed for any single link ring.  Typically, the */
/*    ground tag is the tag of the topmost vertex in the hierarchy.  For     */
/*    instance, if a vertex x has a 2D link, in which a vertex y has a link  */
/*    ring (representing the link of the edge xy), x is generally the ground */
/*    tag.  Hopefully, most of the vertices in x's link share a long prefix  */
/*    with x.                                                                */
/*                                                                           */
/* - At the end (high-index atoms) of every molecule, there is a compressed  */
/*    tag indexing the next molecule in the linked list of molecules.  This  */
/*    compressed tag is written BACKWARD, starting at index MOLECULESIZE - 1,*/
/*    so the least significant atom (whose stop bit is set) has the lowest   */
/*    index of the tag's atoms.  If a molecule is the last one in the linked */
/*    list, its "next molecule" tag is the STOP atom, which occupies just    */
/*    one byte.                                                              */
/*                                                                           */
/*  - The high-order bits of a compressed "next molecule" tag are supplied   */
/*    by the previous tag in the linked list.  (There is not a single        */
/*    "ground tag" as there is for vertex tags.)  This means that "next      */
/*    tags" are often just one byte long, because successive molecules often */
/*    have successive tags.  It also suggests that appending tags to the end */
/*    of a list is more pleasant than splicing them into the middle, which   */
/*    can reduce space efficiency by lengthening the "next molecule" tags.   */
/*                                                                           */
/*  - There are two special atoms, STOP and GHOSTVERTEX (both with their     */
/*    stop bits on).  To prevent confusion, no ordinary tag can compress to  */
/*    either of these.  A tag whose last atom matches STOP or GHOSTVERTEX is */
/*    distinguished by having at least two atoms in its compressed           */
/*    representation (even if it would otherwise compress to one atom).      */
/*                                                                           */
/*  - All bytes of a molecule not occupied by the "next molecule" tag are    */
/*    available for compressed vertices, which are written FORWARD from      */
/*    index zero.  In the last molecule of a linked list, some bytes might   */
/*    be left unused, in which case the last vertex byte must be followed by */
/*    a STOP atom to indicate that not all the bytes are used.  This is only */
/*    permitted in a molecule whose "next molecule" tag is STOP.  If there   */
/*    are no unused bytes in the last molecule of a linked list, then the    */
/*    STOP atom at position MOLECULESIZE - 1 of that molecule does double    */
/*    duty as both the "next molecule" tag and the vertex list terminator.   */
/*                                                                           */
/*  - The compressed tag pointing to the next molecule may occupy at most    */
/*    MOLECULESIZE - 1 bytes (atoms), leaving at least one byte for part of  */
/*    a compressed vertex tag.  (The default molecule size of 16 ought to    */
/*    leave a lot more space for compressed vertices than one byte, but      */
/*    perhaps in some huuuuuge mesh on a 128-bit machine of the future...)   */
/*                                                                           */
/*  - The boundaries between molecules are not related to the boundaries     */
/*    between compressed vertices.  A molecule normally holds several        */
/*    compressed vertices, and a compressed vertex might span two molecules  */
/*    (or more, if the tags are big enough and the molecules small enough).  */
/*                                                                           */
/*  - A link ring should not have any vertex appear twice except the         */
/*    GHOSTVERTEX.  This "invariant" isn't really an invariant, because some */
/*    of the procedures allow you to violate it, and the Bowyer-Watson       */
/*    implementation relies on being able to temporarily have multiple       */
/*    copies of a vertex in a link ring.  (They eventually get merged back   */
/*    into one by linkringdelete2vertices().)  However, this invariant       */
/*    ought to be restored by any algorithm upon completion.                 */
/*                                                                           */
/*  - A link ring cannot have two GHOSTVERTEXs consecutively.                */
/*                                                                           */
/*  - A link ring cannot have exactly one vertex (counting ghost vertices).  */
/*                                                                           */
/*  - A molecule cannot start (index 0) with the STOP vertex, unless the     */
/*    link ring is empty (and this is the sole molecule in the linked list). */
/*    Except in this circumstance, every molecule stores at least one atom   */
/*    from a compressed vertex.  However, the STOP _atom_ can appear at      */
/*    index 0, so long as it is the continuation of a compressed tag from    */
/*    the previous molecule (and therefore it doesn't mean STOP).            */
/*                                                                           */
/*  Here's what a molecule looks like.  Each column is an atom.              */
/*                                                                           */
/*  ------------------------H--------                                        */
/*  |0|0|1|1|0|1|1|0|0|0|1|0H1|0|0|0| <-- Stop bits.  The "next molecule"    */
/*  |1|1|0|0|1|0|1|1|1|0|0|1H0|1|1|0|     tag is written backward and        */
/*  |0|1|1|1|0|0|1|0|1|1|1|1H0|1|1|0|     terminated with a stop bit.  The   */
/*  |1|1|1|0|1|0|1|1|0|1|0|0H0|0|0|1|     vertex tags are written forward    */
/*  |1|0|0|1|1|0|1|1|1|0|1|1H0|0|0|0|     and terminated with a stop bit.    */
/*  |1|1|0|0|1|0|0|0|0|0|0|0H0|1|1|0|     In this example, the last vertex   */
/*  |0|1|1|1|1|0|1|1|1|1|1|1H0|1|0|1|     tag is continued in the next       */
/*  |1|1|0|0|1|1|1|1|1|0|0|1H0|0|1|0|     molecule.                          */
/*  ------------------------H--------                                        */
/*   \_____________________/ \_____/                                         */
/*     compressed vertices    next molecule tag (varies in width)            */
/*                                                                           */
/*  It is permissible to have a link ring with just two vertices (and no     */
/*  ghost vertex).  A link ring with vertices 1 and 2 represents two edges,  */
/*  1-2 and 2-1, which are distinguished by the vertex order (underscoring   */
/*  the importance of a link ring's orientation).                            */
/*                                                                           */
/*  It's also permissible to have a link ring with one "real" vertex and one */
/*  ghost vertex.  This link has no edges at all.  A link can have any       */
/*  number of dangling vertices that are not connected to edges, although    */
/*  I haven't included much support for creating these.  (You can do it by   */
/*  creating an edge, then deleteing one of its vertices.)                   */
/*                                                                           */
/*  The "correct" way to use the linkring interface to build link rings is   */
/*  to use linkringinsertedge() and linkringdeleteedge().  These procedures  */
/*  won't allow you to build invariant-defying link rings.  The procedures   */
/*  that insert and delete individual vertices can accomplish some things    */
/*  faster--inserting a vertex performs a 1 -> 2 bistellar flip (replacing   */
/*  one edge with two), and deleting a vertex performs a 2 -> 1 flip.  But   */
/*  they also allow you to violate invariants; for instance, you could       */
/*  create a link ring with just one vertex by deleting the others.  The     */
/*  Bowyer-Watson implementation exploits the fact that you can insert       */
/*  multiple copies of a vertex into a link ring, but it's careful to clean  */
/*  up after itself in the end.                                              */
/*                                                                           */
/*  Public interface:                                                        */
/*  GHOSTVERTEX   Tag representing a ghost vertex.                           */
/*  STOP   Tag representing an unsuccessful query.                           */
/*  struct linkposition   Represents a position in a link ring or 2D link.   */
/*  tag linkringnew(pool, allocindex)   Allocate a new, empty link ring.     */
/*  tag linkringnewfill(pool, groundtag, tagarray, tagarraylen, allocindex)  */
/*    Allocate a new link ring containing the tags specified in the input.   */
/*  void linkringrestart(pool, linkring)   Reset a link ring to empty.       */
/*  void linkringdelete(pool, linkring)   Free a link ring to the pool.      */
/*  int linkringadjacencies(pool, linkring, groundtag, searchvertex,         */
/*    adjacencies[2])   Read the two vertices neighboring a vertex in link.  */
/*  void linkringiteratorinit(pool, linkring, pos)   Initialize an iterator  */
/*    that traverses all the vertices in a link ring one by one.             */
/*  tag linkringiterate(pos)   Read and advance iterator.                    */
/*  void linkringprint(pool, linkring, groundtag)   Print a link ring.       */
/*  int linkringinsertedge(pool, linkring, groundtag, endpoint1, endpoint2)  */
/*    Insert an edge into a link ring.                                       */
/*  int linkringdeleteedge(pool, linkring, groundtag, endpoint1, endpoint2)  */
/*    Delete an edge from a link ring.                                       */
/*  int linkringinsertvertex(pool, linkring, groundtag, searchvertex,        */
/*    newvertex)   Insert a vertex in link, following a specified vertex.    */
/*  int linkringdeletevertex(pool, linkring, groundtag, deletevertex)        */
/*    Delete a vertex from a link ring.                                      */
/*  int linkringdelete2vertices(pool, linkring, groundtag, deletevertex)     */
/*    Delete a vertex and the vertex that follows it from a link ring.       */
/*                                                                           */
/*  For internal use only:                                                   */
/*  struct linkpossmall   Represents a position in a link ring or 2D link.   */
/*  int linkringtagcompress(groundtag, newtag, newtagatoms)                  */
/*  void linkringreadtag(moleculetag, cule, atomindex, nextmoleculetag,      */
/*    nowatom, errstring)                                                    */
/*  int linkringadjacencies2(pool, linkring, groundtag, searchvertex,        */
/*    adjacencies[2])                                                        */
/*  tag linkringinsertatoms(pool, insertposition, numatoms, newatombuffer,   */
/*    allocindex)                                                            */
/*  tag linkringinsertatoms2(pool, insertposition, numatoms, newatombuffer,  */
/*    allocindex)                                                            */
/*  tag linkringdeleteatoms(pool, deleteposition, numatoms)                  */
/*  tag linkringdeleteatoms2(pool, deleteposition, numatoms)                 */
/*  void linkringrotateatoms(pool, linkring, pos1, pos2)                     */
/*                                                                           */
/*****************************************************************************/


/*  `molecule' is a short piece of memory, with room for MOLECULESIZE atoms  */
/*  (characters).  Link rings are made up of molecules chained together in   */
/*  linked lists.  Each molecule has a compressed tag at the end which       */
/*  points to the next molecule in the list.  The rest of its space is       */
/*  devoted to compressed tags indexing vertices in the link ring.           */
/*                                                                           */
/*  2D links are also made of chains of molecules, with the compressed tags  */
/*  indexing both vertices and link rings.                                   */
/*                                                                           */
/*  The declaration "typedef char molecule[MOLECULESIZE]" would have been    */
/*  more appropriate, if C interpreted that as a reassignable pointer to an  */
/*  array of size MOLECULESIZE.  All molecules are the same size.            */

typedef char *molecule;


/*  GHOSTVERTEX is a tag that represents a "ghost vertex," which represents  */
/*  a gap in a link ring or a simplicial complex.  If a ghost vertex lies    */
/*  between vertices v and w in a link ring, it means that vw is not an edge */
/*  of the link, even though v and w are successive vertices in the link.    */
/*  To give another example, if a tetrahedron has a face f not shared by     */
/*  another tetrahedron in the simplicial complex, we represent it as        */
/*  sharing a face with a "ghost tetrahedron" whose fourth vertex is the     */
/*  ghost vertex.  Cast to a character, GHOSTVERTEX is also an atom that     */
/*  serves as the compressed form of the GHOSTVERTEX tag.                    */
/*                                                                           */
/*  STOP is a tag used to terminate a sequence of atoms in a molecule,       */
/*  implying either that the atoms continue in the next molecule, or there   */
/*  are no more atoms in the link ring.  STOP is also used as a "next tag"   */
/*  index at the end of a molecule, to indicate that it is the last molecule */
/*  in the linked list.  The STOP tag is not part of the interface of any of */
/*  the linkring procedures, but it is returned by some of the link2d        */
/*  procedures.  Cast to a character, STOP is the one-atom compressed form   */
/*  of the STOP tag.                                                         */

#define GHOSTVERTEX (~ (tag) 0)
#define STOP (~ (tag) 1)

/*  MOLECULESIZE is the size of one molecule in characters (and atoms).      */
/*  The choice makes a trade-off between wasted space (most compressed link  */
/*  rings do not use the entirely of the last molecule in their linked       */
/*  lists) and space occupied by the compressed "next molecule tag" index    */
/*  (which is space that can't be used for compressed vertices).  To obtain  */
/*  high speed, 20 seems to be a good choice.  (Higher values don't buy much */
/*  more speed, but cost a lot of memory.)  To obtain maximum compactness,   */
/*  8 is a good choice.                                                      */

#define MOLECULESIZE 20

/*  MOLECULEQUEUESIZE is the number of molecules that linkringdeleteatoms()  */
/*  can remember at once.  linkringdeleteatoms() should not be asked to      */
/*  delete more than this many molecules' atoms at once.  Fortunately, the   */
/*  maximum number of atoms that any procedure wants to delete at once is no */
/*  more than three compressed vertices' worth.                              */

#define MOLECULEQUEUESIZE 40

/*  COMPRESSEDTAGLENGTH is an upper bound on the maximum number of bytes a   */
/*  tag occupies after it is compressed.  Used to allocate buffers for       */
/*  atoms in transit.                                                        */

#define COMPRESSEDTAGLENGTH (8 * sizeof(tag) / 7 + 2)


/*  A linkposition represents an atom in a link ring or 2D link.  Usually,   */
/*  the atom is the first atom in some compressed vertex, or the STOP tag at */
/*  the end of the linked list.  Among other things, this struct is useful   */
/*  as an iterator that walks through a link ring or 2D link.                */
/*                                                                           */
/*  The atom in question appears at index `textindex' in molecule `cule',    */
/*  usually.  However, if textindex > lasttextindex, the atom in question is */
/*  really the first atom of the next molecule in the linked list.  This may */
/*  seem oblique, but it's sometimes useful.  For instance, when deleting    */
/*  atoms at a given position in a link ring, this representation increases  */
/*  the likelihood of being able to free an additional molecule at the end   */
/*  of the linked list for reuse elsewhere.                                  */
/*                                                                           */
/*  `moleculetag' is the tag of the current molecule (which is needed for    */
/*  use as a base for compressing the next tag when a new molecule gets      */
/*  appended to the linked list).  `lasttextindex' is the index of the last  */
/*  index in this tag used for compressed vertices (as opposed to the "next  */
/*  molecule tag").  `nextmoleculetag' is the tag of the next molecule in    */
/*  the linked list (possibly STOP).  These two fields are stored so that    */
/*  they only need to be computed once, when `cule' is first encountered.    */

struct linkposition {
  molecule cule;      /* The molecule containing the atom (or right before). */
  int textindex;                                   /* The index of the atom. */
  int lasttextindex;   /* The last atom not part of the "next molecule" tag. */
  tag moleculetag;                       /* The tag for the molecule `cule'. */
  tag nextmoleculetag;  /* The next tag following `moleculetag' in the list. */
  tag groundtag;            /* Tag for the link's owner, used to decompress. */
  struct proxipool *pool;  /* The pool in which the molecules are allocated. */
};

/*  A smaller version of a linkposition, used internally only.               */

struct linkpossmall {
  molecule cule;      /* The molecule containing the atom (or right before). */
  int textindex;                                   /* The index of the atom. */
  int lasttextindex;   /* The last atom not part of the "next molecule" tag. */
  tag moleculetag;                       /* The tag for the molecule `cule'. */
  tag nextmoleculetag;  /* The next tag following `moleculetag' in the list. */
};


/*****************************************************************************/
/*                                                                           */
/*  linkringtagcompress()   Compresses a tag, relative to another tag.       */
/*                                                                           */
/*  The compressed tag contains enough lower-order bits of the original      */
/*  tag to distinguish it from another tag, `groundtag'.  Decompression can  */
/*  be done later simply by using `groundtag' as the source of the missing   */
/*  high-order bits.                                                         */
/*                                                                           */
/*  The low-order bits are partitioned into atoms (7-bit chunks), and the    */
/*  high-order "stop bit" of the lowest-order atom is set.                   */
/*                                                                           */
/*  The compressed tag is always at least one atom long, even if `newtag' == */
/*  `groundtag'.  If `newtag' is STOP or GHOSTVERTEX, the compressed tag is  */
/*  just one atom long.  Otherwise, if the last atom of `newtag' is STOP or  */
/*  GHOSTVERTEX, then the compressed tag is at least two atoms long, so that */
/*  it cannot be mistaken for STOP or GHOSTVERTEX.                           */
/*                                                                           */
/*  IMPORTANT:  The atoms are written into the array `newtagatoms' in        */
/*  REVERSE order, with the least significant atom (with its stop bit set)   */
/*  at index zero.  (This is the right order for "next molecule" tags, but   */
/*  compressed vertices need to be reversed back.)                           */
/*                                                                           */
/*  groundtag:  The base tag against which `newtag' is compressed.           */
/*  newtag:  The tag to compress.                                            */
/*  newtagatoms:  The array into which the compressed tag's atoms are        */
/*    written BACKWARD.                                                      */
/*                                                                           */
/*  Returns the number of atoms in the compressed tag.                       */
/*                                                                           */
/*****************************************************************************/

int linkringtagcompress(tag groundtag,
                        tag newtag,
                        char *newtagatoms)
{
  int numatoms;

  /* Extract the least significant atom; set its stop bit. */
  newtagatoms[0] = (char) ((newtag & (tag) 127) | (tag) ~127);
  if ((newtag == GHOSTVERTEX) || (newtag == STOP)) {
    /* GHOSTVERTEX and STOP always compress to one atom. */
    return 1;
  }

  /* Cut the least significant atoms from the tag and the ground tag. */
  groundtag = groundtag >> 7;
  newtag = newtag >> 7;
  numatoms = 1;
  /* Keep cutting atoms until the two tags' remaining bits agree. */
  while (groundtag != newtag) {
    /* Extract the next atom. */
    newtagatoms[numatoms] = (char) (newtag & (tag) 127);
    /* Cut it off in anticipation of the next comparison. */
    groundtag = groundtag >> 7;
    newtag = newtag >> 7;
    numatoms++;
  }

  if ((numatoms == 1) &&
      ((newtagatoms[0] == (char) GHOSTVERTEX) ||
       (newtagatoms[0] == (char) STOP))) {
    /* To avoid confusion, any tag whose least significant atom matches the */
    /*   ghost vertex or STOP atom has to compress to at least two atoms.   */
    newtagatoms[1] = (char) (newtag & (tag) 127);
    numatoms++;
  }

  return numatoms;
}

/*****************************************************************************/
/*                                                                           */
/*  linkringnew()   Allocate a new, empty link ring.                         */
/*                                                                           */
/*  The parameters include an allocation index, used to determine where the  */
/*  new link ring will be stored in memory.  Link rings with the same        */
/*  allocation index go into common areas in memory.  The idea is to create  */
/*  spatial coherence:  links that are geometrically close to each other are */
/*  near each other in memory, too.                                          */
/*                                                                           */
/*  The parameters include the coordinates of a point associated with the    */
/*  link ring, so that the link ring can be allocated from memory near other */
/*  molecules that are spatially nearby.                                     */
/*                                                                           */
/*  pool:  The proxipool to allocate the link ring from.                     */
/*  allocindex:  An allocation index associated with the link ring.          */
/*                                                                           */
/*  Returns the tag of the first (and only) molecule of the new link ring.   */
/*                                                                           */
/*****************************************************************************/

tag linkringnew(struct proxipool *pool,
                proxipoolulong allocindex)
{
  molecule cule;
  tag newlinkring;

  /* Allocate a molecule to hold the (empty) link ring. */
  newlinkring = proxipoolnew(pool, allocindex, (void **) &cule);
  /* There are no vertices in this link ring. */
  cule[0] = (char) STOP;
  /* There is no next molecule. */
  cule[MOLECULESIZE - 1] = (char) STOP;
  return newlinkring;
}

/*****************************************************************************/
/*                                                                           */
/*  linkringnewfill()   Allocate a new link ring containing the tags         */
/*                      (vertices) specified in an input array.              */
/*                                                                           */
/*  The tags may include GHOSTVERTEX.  Be sure to obey the link ring         */
/*  invariants:  no vertex except GHOSTVERTEX may occur twice in a link      */
/*  ring, and GHOSTVERTEX may not occur twice consecutively.  (Remember      */
/*  that the link ring is a ring, so GHOSTVERTEX may not occur both first    */
/*  and last.)                                                               */
/*                                                                           */
/*  pool:  The proxipool to allocate the link ring from.                     */
/*  groundtag:  The ground tag that serves as a base for the compression of  */
/*    the other tags.                                                        */
/*  tagarray:  An array listing the tags to put in the link ring.            */
/*  tagarraylen:  The number of tags to put in the link ring.                */
/*  allocindex:  An allocation index associated with the link ring.          */
/*                                                                           */
/*  Returns the tag of the first molecule of the link ring.                  */
/*                                                                           */
/*****************************************************************************/

tag linkringnewfill(struct proxipool *pool,
                    tag groundtag,
                    tag *tagarray,
                    proxipoolulong tagarraylen,
                    proxipoolulong allocindex)
{
  molecule cule;
  molecule nextcule;
  tag newlinkring;
  tag moleculetag;
  tag nextculetag;
  proxipoolulong tagarrayindex;
  int vertexatomcount;
  int vertexwriteindex;
  int vertexcopyindex;
  int vertexleftindex;
  int tagsize;
  int nextculeindex;
  int i;
  char atombuffer[MOLECULESIZE + 3 * COMPRESSEDTAGLENGTH];
  unsigned int aftervertexindex[MOLECULESIZE + 3 * COMPRESSEDTAGLENGTH];

  /* Allocate the first molecule of the new link ring. */
  newlinkring = proxipoolnew(pool, allocindex, (void **) &cule);
  moleculetag = newlinkring;

  /* Compress the first tag (if there is any) into `atombuffer'. */
  vertexatomcount = tagarraylen <= 0 ? 0 :
                    linkringtagcompress(groundtag, tagarray[0], atombuffer);
  /* Compressed tags are written backward by linkringtagcompress(), so the */
  /*   compressed tag will be copied from index `vertexcopyindex' back to  */
  /*   index `vertexleftindex' (presently zero).                           */
  vertexleftindex = 0;
  vertexcopyindex = vertexatomcount - 1;
  /* Keep track of where this compressed vertex ends, and the second vertex */
  /*   will begin.                                                          */
  aftervertexindex[0] = vertexatomcount;
  vertexwriteindex = vertexatomcount;
  /* The second vertex has index one. */
  tagarrayindex = 1;
  nextcule = (molecule) NULL;
  nextculetag = 0;

  /* The outer loop fills one molecule per iteration. */
  do {
    /* The next loop compresses enough tags to yield MOLECULESIZE atoms */
    /*   (unless we run out of tags).                                   */
    while ((tagarrayindex < tagarraylen) && (vertexatomcount < MOLECULESIZE)) {
      /* Compress the next tag into the buffer. */
      tagsize = linkringtagcompress(groundtag, tagarray[tagarrayindex],
                                    &atombuffer[vertexwriteindex]);
      tagarrayindex++;
      /* Keep track of the number of atoms waiting to be put into link ring. */
      vertexatomcount += tagsize;
      /* Keep track of where this compressed vertex ends. */
      aftervertexindex[vertexwriteindex] = vertexwriteindex + tagsize;
      vertexwriteindex += tagsize;
      /* If too close to the end of the buffer, return to the beginning */
      /*   for the next vertex.                                         */
      if (vertexwriteindex > MOLECULESIZE + 2 * COMPRESSEDTAGLENGTH) {
        vertexwriteindex = 0;
      }
    }

    /* Check if this is the last molecule in the link ring. */
    if (vertexatomcount >= MOLECULESIZE) {
      /* Too many atoms left to fit in one molecule.  Allocate another one. */
      nextculetag = proxipoolnew(pool, allocindex, (void **) &nextcule);
      /* Compress the "next molecule" tag and figure where to put it. */
      nextculeindex = MOLECULESIZE -
                      linkringtagcompress(moleculetag, nextculetag,
                                          (char *) cule);
      /* Shift the compressed tag from the left to the right side of `cule'. */
      for (i = nextculeindex; i < MOLECULESIZE; i++) {
        cule[i] = cule[i - nextculeindex];
      }
    } else {
      /* Write a STOP atom after the last vertex. */
      cule[vertexatomcount] = (char) STOP;
      /* Write a STOP atom for the "next molecule" tag. */
      cule[MOLECULESIZE - 1] = (char) STOP;
      /* Set up `nextculeindex' for the upcoming loop. */
      nextculeindex = vertexatomcount;
    }

    /* Fill the rest of the molecule with atoms. */
    for (i = 0; i < nextculeindex; i++) {
      cule[i] = atombuffer[vertexcopyindex];
      /* Tags are compressed backward, so we reverse them back to forward. */
      vertexcopyindex--;
      /* Have we just written the last atom of a vertex? */
      if (vertexcopyindex < vertexleftindex) {
        /* Yes.  Jump to the next vertex. */
        vertexleftindex = aftervertexindex[vertexleftindex];
        /* If too close to the end of the buffer, return to the beginning */
        /*   (following the process that wrote the buffer).               */
        if (vertexleftindex > MOLECULESIZE + 2 * COMPRESSEDTAGLENGTH) {
          vertexleftindex = 0;
        }
        /* Find the rightmost atom of this compressed vertex. */
        vertexcopyindex = aftervertexindex[vertexleftindex] - 1;
      }
    }
    /* How many atoms in the buffer still await copying? */
    vertexatomcount -= nextculeindex;

    /* Go on to the next molecule in the next iteration. */
    cule = nextcule;
    moleculetag = nextculetag;
  } while (vertexatomcount > 0);

  return newlinkring;
}

/*****************************************************************************/
/*                                                                           */
/*  linkringreadtag()   Read the "next molecule" tag from a molecule.        */
/*                                                                           */
/*  This macro is a sequence of operations repeated in a bunch of the        */
/*  linkring procedures.  It's repeated often enough that it's worth         */
/*  inlining; hence, I've made it a macro.                                   */
/*                                                                           */
/*  moleculetag:  Used as a ground tag for decompressing `nextmoleculetag'   */
/*    (input, not changed).                                                  */
/*  cule:  The molecule to read (input, not changed).                        */
/*  atomindex:  Output only, whereupon it is the last index devoted to       */
/*    compressed vertices (i.e. one before the first index devoted to the    */
/*    compressed "next molecule" tag) in `cule'.                             */
/*  nextmoleculetag:  Output only, whereupon it is the tag for the next      */
/*    molecule after `cule' in the linked list.                              */
/*  nowatom:  A work variable; neither input nor output.                     */
/*  errstring:  A string to print if there's an unrecoverable error.         */
/*                                                                           */
/*****************************************************************************/

#define linkringreadtag(moleculetag, cule, atomindex, nextmoleculetag,  \
                        nowatom, errstring)  \
  nowatom = cule[MOLECULESIZE - 1];  \
  atomindex = MOLECULESIZE - 2;  \
  if (nowatom == (char) STOP) {  \
    nextmoleculetag = STOP;  \
  } else {  \
    nextmoleculetag = nowatom & (char) 127;  \
    while (nowatom >= (char) 0) {  \
      if (atomindex < 0) {  \
        printf(errstring);  \
        printf("  Tag for next molecule not properly terminated.\n");  \
        internalerror();  \
      }  \
      nowatom = cule[atomindex];  \
      nextmoleculetag = (nextmoleculetag << 7) + (nowatom & (char) 127);  \
      atomindex--;  \
    }  \
    nextmoleculetag += (moleculetag >>  \
                        (7 * (MOLECULESIZE - 1 - atomindex))) <<  \
                       (7 * (MOLECULESIZE - 1 - atomindex));  \
  }

/*****************************************************************************/
/*                                                                           */
/*  linkringrestart()   Reset a link ring to empty.                          */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from.              */
/*  linkring:  Tag for the first molecule in the link ring.                  */
/*                                                                           */
/*****************************************************************************/

void linkringrestart(struct proxipool *pool,
                     tag linkring)
{
  molecule cule;
  tag nextmoleculetag;
  tag moleculetag;
  int atomindex;
  char nowatom;

  if (linkring >= STOP) {
    return;
  }

  moleculetag = linkring;

  /* Loop through the molecules and free all but the first. */
  do {
    /* Convert the tag to a molecule. */
    cule = (molecule) proxipooltag2object(pool, moleculetag);
    /* Read the "next molecule" tag. */
    linkringreadtag(moleculetag, cule, atomindex, nextmoleculetag, nowatom,
                    "Internal error in linkringrestart():\n");
    if (moleculetag == linkring) {
      /* There are no vertices in the first link ring. */
      cule[0] = (char) STOP;
      /* There is no next molecule. */
      cule[MOLECULESIZE - 1] = (char) STOP;
    } else {
      /* Free the molecule. */
      proxipoolfree(pool, moleculetag);
    }
    moleculetag = nextmoleculetag;
  } while (nextmoleculetag != STOP);
}

/*****************************************************************************/
/*                                                                           */
/*  linkringdelete()   Free all the molecules in a link ring to the pool.    */
/*                                                                           */
/*  pool:  The proxipool that the molecules were allocated from.             */
/*  linkring:  Tag for the first molecule in the link ring.                  */
/*                                                                           */
/*****************************************************************************/

void linkringdelete(struct proxipool *pool,
                    tag linkring)
{
  molecule cule;
  tag nextmoleculetag;
  tag moleculetag;
  int atomindex;
  char nowatom;

  if (linkring >= STOP) {
    return;
  }

  moleculetag = linkring;

  /* Loop through the molecules and free them. */
  do {
    /* Convert the tag to a molecule. */
    cule = (molecule) proxipooltag2object(pool, moleculetag);
    /* Read the "next molecule" tag. */
    linkringreadtag(moleculetag, cule, atomindex, nextmoleculetag, nowatom,
                    "Internal error in linkringdelete():\n");
    /* Free the molecule. */
    proxipoolfree(pool, moleculetag);
    moleculetag = nextmoleculetag;
  } while (nextmoleculetag != STOP);
}

/*****************************************************************************/
/*                                                                           */
/*  linkringadjacencies()    Return the two neighboring vertices adjoining a */
/*  linkringadjacencies2()   vertex in a link ring.                          */
/*                                                                           */
/*  These procedures are interchangeable.  linkringadjacencies2() is a       */
/*  complete implementation.  linkringadjacencies() is an optimized wrapper  */
/*  that handles the special case where the entire link ring fits in a       */
/*  single molecule faster, and calls linkringadjacencies2() otherwise.      */
/*  Profiling suggests that when MOLECULESIZE is 20, linkringadjacencies()   */
/*  resorts to calling linkringadjacencies2() only 2.5% of the time.         */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from.              */
/*  linkring:  Tag for the first molecule in the link ring.                  */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  searchvertex:  The tag of the vertex to search for.                      */
/*  adjacencies[2]:  Array in which the procedure returns the tags of the    */
/*    vertices adjacent to `searchvertex'.  adjacencies[0] is just before    */
/*    (clockwise from) `searchvertex', and adjacencies[1] is just after      */
/*    (counterclockwise from) `searchvertex'.  One or both of these may be   */
/*    GHOSTVERTEX, if `searchvertex' does not participate in two edges of    */
/*    the link ring.  The contents of this array do not need to be           */
/*    initialized prior to calling this procedure.                           */
/*                                                                           */
/*  Returns 1 if `searchvertex' is in the link ring; 0 otherwise.            */
/*                                                                           */
/*****************************************************************************/

int linkringadjacencies2(struct proxipool *pool,
                         tag linkring,
                         tag groundtag,
                         tag searchvertex,
                         tag adjacencies[2])
{
  molecule cule;
  tag vertextag;
  tag firstvertextag;
  tag prevvertextag;
  tag nextmoleculetag;
  tag moleculetag;
  long vertexcount;
  int vertexatoms;
  int atomindex1, atomindex2;
  char nowatom;

  if (linkring >= STOP) {
    /* Not a link ring. */
    adjacencies[0] = GHOSTVERTEX;
    adjacencies[1] = GHOSTVERTEX;
    return 0;
  }

  /* There is no "previous" vertex we've visited yet. */
  firstvertextag = STOP;
  prevvertextag = STOP;
  vertexcount = 0;
  vertextag = 0;
  vertexatoms = 0;
  /* Start at the first molecule. */
  nextmoleculetag = linkring;

  /* Loop through the linked list of molecules. */
  do {
    /* Convert the molecule's tag to a pointer. */
    cule = (molecule) proxipooltag2object(pool, nextmoleculetag);
    moleculetag = nextmoleculetag;
    /* Read the "next molecule" tag. */
    linkringreadtag(moleculetag, cule, atomindex2, nextmoleculetag, nowatom,
                    "Internal error in linkringadjacencies():\n");

    atomindex1 = 0;
    /* Loop through the atoms, stopping at the "next molecule" tag. */
    while (atomindex1 <= atomindex2) {
      nowatom = cule[atomindex1];
      /* Append the atom to the vertex tag. */
      vertextag = (vertextag << 7) + (nowatom & (char) 127);
      vertexatoms++;
      atomindex1++;

      /* Is this the last atom in the compressed tag? */
      if (nowatom < (char) 0) {
        /* Yes; we have an uncompressed tag now.  What tag is it? */
        if ((nowatom == (char) STOP) && (vertexatoms == 1)) {
          /* STOP tag.  Exit the inner loop early; go on to next molecule. */
          break;
        } else if ((nowatom == (char) GHOSTVERTEX) && (vertexatoms == 1)) {
          /* Ghost vertex. */
          vertextag = GHOSTVERTEX;
        } else {
          /* Use the ground tag to supply the high-order bits. */
          vertextag += (groundtag >> (7 * vertexatoms)) << (7 * vertexatoms);
        }

        vertexcount++;
        /* Is this the vertex we're searching for? */
        if (vertextag == searchvertex) {
          /* Yes.  Output the previous vertex.  (If we're at the start of  */
          /*   the list, `prevvertextag' is STOP, but we'll fix it later.) */
          adjacencies[0] = prevvertextag;
        }

        if (vertexcount == 1) {
          /* This is the first vertex.  Remember it. */
          firstvertextag = vertextag;
        } else if (prevvertextag == searchvertex) {
          /* The previous vertex was `searchvertex', so output this vertex. */
          adjacencies[1] = vertextag;
          /* Return early...unless `searchvertex' was at the start of the  */
          /*   list, in which case one neighbor is at the end of the list. */
          if (vertexcount > 2) {
            return 1;
          }
        }

        /* Remember this tag during the next iteration. */
        prevvertextag = vertextag;
        /* Prepare to read another tag. */
        vertextag = 0;
        vertexatoms = 0;
      }
    }
  } while (nextmoleculetag != STOP);

  if (nowatom >= (char) 0) {
    /* Oops.  The end of the last vertex is missing from the last molecule. */
    printf("Internal error in linkringadjacencies():\n");
    printf("  Vertex at end of link ring not properly terminated.\n");
    internalerror();
  }

  /* The link ring is circular, so check the first and last vertices. */
  if (prevvertextag == searchvertex) {
    /* The last vertex is `searchvertex', so output the first vertex. */
    adjacencies[1] = firstvertextag;
    if (vertexcount == 1) {
      /* There is only one vertex in the ring. */
      adjacencies[0] = firstvertextag;
    }
    return 1;
  } else if (firstvertextag == searchvertex) {
    /* The first vertex is `searchvertex', so output the last vertex. */
    adjacencies[0] = prevvertextag;
    return 1;
  } else {
    /* Execution can only get this far if `searchvertex' is not in the ring. */
    adjacencies[0] = GHOSTVERTEX;
    adjacencies[1] = GHOSTVERTEX;
    return 0;
  }
}

/*****************************************************************************/
/*                                                                           */
/*  linkringadjacencies()   Return the two neighboring vertices adjoining a  */
/*                          vertex in a link ring.                           */
/*                                                                           */
/*  See header above linkringadjacencies2().                                 */
/*                                                                           */
/*****************************************************************************/

int linkringadjacencies(struct proxipool *pool,
                        tag linkring,
                        tag groundtag,
                        tag searchvertex,
                        tag adjacencies[2])
{
  molecule cule;
  tag vertextag;
  tag firstvertextag;
  tag prevvertextag;
  long vertexcount;
  int vertexatoms;
  int atomindex;
  char nowatom;

  if (linkring >= STOP) {
    /* Not a link ring. */
    adjacencies[0] = GHOSTVERTEX;
    adjacencies[1] = GHOSTVERTEX;
    return 0;
  }

  /* Convert the molecule's tag to a pointer. */
  cule = (molecule) proxipooltag2object(pool, linkring);
  /* Is the list just one molecule? */
  if (cule[MOLECULESIZE - 1] == (char) STOP) {
    /* Yes.  Run a faster lookup. */

    /* There is no "previous" vertex we've visited yet. */
    firstvertextag = STOP;
    prevvertextag = STOP;
    vertexcount = 0;
    vertextag = 0;
    vertexatoms = 0;

    atomindex = 0;
    /* Loop through the atoms, stopping at the "next molecule" tag. */
    while (1) {
      nowatom = cule[atomindex];
      /* Append the atom to the vertex tag. */
      vertextag = (vertextag << 7) + (nowatom & (char) 127);
      vertexatoms++;
      atomindex++;

      /* Is this the last atom in the compressed tag? */
      if (nowatom < (char) 0) {
        /* Yes; we have an uncompressed tag now.  What tag is it? */
        if (((nowatom == (char) STOP) && (vertexatoms == 1)) ||
            (atomindex >= MOLECULESIZE)) {
          /* STOP tag.  End of the list.  The link ring is circular, so */
          /*   check the first and last vertices.                       */
          if (prevvertextag == searchvertex) {
            /* The last vertex is `searchvertex', so output the first */
            /*   vertex.                                              */
            adjacencies[1] = firstvertextag;
            if (vertexcount == 1) {
              /* There is only one vertex in the ring. */
              adjacencies[0] = firstvertextag;
            }
            return 1;
          } else if (firstvertextag == searchvertex) {
            /* The first vertex is `searchvertex', so output the last */
            /*   vertex.                                              */
            adjacencies[0] = prevvertextag;
            return 1;
          }
          /* `searchvertex' is not in the ring. */
          adjacencies[0] = GHOSTVERTEX;
          adjacencies[1] = GHOSTVERTEX;
          return 0;
        } else if ((nowatom == (char) GHOSTVERTEX) && (vertexatoms == 1)) {
          /* Ghost vertex. */
          vertextag = GHOSTVERTEX;
        } else {
          /* Use the ground tag to supply the high-order bits. */
          vertextag += (groundtag >> (7 * vertexatoms)) << (7 * vertexatoms);
        }

        vertexcount++;
        /* Is this the vertex we're searching for? */
        if (vertextag == searchvertex) {
          /* Yes.  Output the previous vertex.  (If we're at the start of  */
          /*   the list, `prevvertextag' is STOP, but we'll fix it later.) */
          adjacencies[0] = prevvertextag;
        }

        if (vertexcount == 1) {
          /* This is the first vertex.  Remember it. */
          firstvertextag = vertextag;
        } else if (prevvertextag == searchvertex) {
          /* The previous vertex was `searchvertex', so output this vertex. */
          adjacencies[1] = vertextag;
          /* Return early...unless `searchvertex' was at the start of the  */
          /*   list, in which case one neighbor is at the end of the list. */
          if (vertexcount > 2) {
            return 1;
          }
        }

        /* Remember this tag during the next iteration. */
        prevvertextag = vertextag;
        /* Prepare to read another tag. */
        vertextag = 0;
        vertexatoms = 0;
      }
    }
  } else {
    /* The list does not fit in one molecule.  Do it the general (slow) way. */
    return linkringadjacencies2(pool, linkring, groundtag, searchvertex,
                                adjacencies);
  }
}

/*****************************************************************************/
/*                                                                           */
/*  linkringiteratorinit()   Initialize an iterator that traverses all the   */
/*                           vertices in a link ring (including ghost        */
/*                           vertices) one by one.                           */
/*                                                                           */
/*  The iterator is a variable `pos', whose internals should not be          */
/*  examined or modified by the client.  The iterator's job is to keep       */
/*  track of where it is in the link ring.  This procedure sets the iterator */
/*  to reference the first vertex in the link ring.                          */
/*                                                                           */
/*  After a link ring is modified, any iterators on that link ring may be    */
/*  corrupted and should not be used without being initialized (by this      */
/*  procedure) again.                                                        */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from.              */
/*  linkring:  The link ring to traverse.                                    */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  pos:  The iterator.  Its contents do not need to be initialized prior to */
/*    calling this procedure.                                                */
/*                                                                           */
/*****************************************************************************/

void linkringiteratorinit(struct proxipool *pool,
                          tag linkring,
                          tag groundtag,
                          struct linkposition *pos)
{
  char nowatom;

  pos->pool = pool;
  pos->groundtag = groundtag;

  if (linkring >= STOP) {
    pos->cule = (molecule) NULL;
    pos->moleculetag = STOP;
    pos->nextmoleculetag = STOP;
    pos->textindex = MOLECULESIZE;
    pos->lasttextindex = -1;
    return;
  }

  pos->moleculetag = linkring;
  /* Find the molecule identified by the tag `linkring'. */
  pos->cule = (molecule) proxipooltag2object(pool, linkring);
  /* Read the molecule's "next molecule" tag. */
  linkringreadtag(linkring, pos->cule, pos->lasttextindex,
                  pos->nextmoleculetag, nowatom,
                  "Internal error in linkringiteratorinit():\n");
  /* Start the iterations from the beginning of the molecule. */
  pos->textindex = 0;
}

/*****************************************************************************/
/*                                                                           */
/*  linkringiterate()   Return the tag that a link ring iterator references, */
/*                      and advance the iterator so it will return the next  */
/*                      vertex next time.                                    */
/*                                                                           */
/*  The iterator is a variable `pos', whose internals should not be          */
/*  examined or modified by the client.                                      */
/*                                                                           */
/*  After a link ring is modified, any iterators on that link ring created   */
/*  before the modification may be corrupted and should not be passed to     */
/*  this procedure again until they are initialized again.                   */
/*                                                                           */
/*  pos:  The iterator.                                                      */
/*                                                                           */
/*  Returns the tag of a vertex in the link ring (possibly GHOSTVERTEX), or  */
/*    STOP if the iterator is at the end of the link ring.                   */
/*                                                                           */
/*****************************************************************************/

tag linkringiterate(struct linkposition *pos)
{
  tag vertextag;
  int vertexatoms;
  char nowatom;

  vertextag = 0;
  vertexatoms = 0;

  /* Loop through atoms to build up one vertex tag. */
  do {
    /* Have we read the last vertex atom in this molecule? */
    while ((pos->textindex > pos->lasttextindex) ||
           ((pos->cule[pos->textindex] == (char) STOP) &&
            (vertexatoms == 0))) {
      /* Yes, we have.  Are there any more molecules after this one? */
      if (pos->nextmoleculetag == STOP) {
        /* No, there aren't.  The iterator is finished. */
        return STOP;
      }

      /* Find the next molecule in the linked list. */
      pos->cule = (molecule) proxipooltag2object(pos->pool,
                                                 pos->nextmoleculetag);
      pos->moleculetag = pos->nextmoleculetag;
      /* Read the next molecule's "next molecule" tag. */
      linkringreadtag(pos->moleculetag, pos->cule, pos->lasttextindex,
                      pos->nextmoleculetag, nowatom,
                      "Internal error in linkringiterate():\n");
      /* Start from the beginning of this molecule. */
      pos->textindex = 0;
    }

    /* Read the next atom. */
    nowatom = pos->cule[pos->textindex];
    /* Append it to the tag. */
    vertextag = (vertextag << 7) + (nowatom & (char) 127);
    vertexatoms++;
    pos->textindex++;
    /* End the loop when `nowatom' has a stop bit (i.e. is negative). */
  } while (nowatom >= (char) 0);

  if ((nowatom == (char) GHOSTVERTEX) && (vertexatoms == 1)) {
    return GHOSTVERTEX;
  } else {
    /* Get the high-order bits from the ground tag. */
    vertextag += (pos->groundtag >> (7 * vertexatoms)) << (7 * vertexatoms);
    return vertextag;
  }
}

/*****************************************************************************/
/*                                                                           */
/*  linkringprint()   Print the contents of a link ring.                     */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from.              */
/*  linkring:  Tag for the first molecule in the link ring.                  */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*                                                                           */
/*****************************************************************************/

void linkringprint(struct proxipool *pool,
                   tag linkring,
                   tag groundtag)
{
  struct linkposition pos;
  tag nexttag;

  printf("Ring %lu: ", (unsigned long) linkring);
  linkringiteratorinit(pool, linkring, groundtag, &pos);
  nexttag = linkringiterate(&pos);
  if (nexttag == STOP) {
    printf("EMPTY");
  } else do {
    if (nexttag == GHOSTVERTEX) {
      printf("GHOST ");
    } else {
      printf("%lu ", (unsigned long) nexttag);
    }
    nexttag = linkringiterate(&pos);
  } while (nexttag != STOP);
  printf("\n");
}

/*****************************************************************************/
/*                                                                           */
/*  linkringinsertatoms()    Insert atoms at a specified position in a link  */
/*  linkringinsertatoms2()   ring (moving the other atoms back to make       */
/*                           room).                                          */
/*                                                                           */
/*  These procedures are interchangeable.  linkringinsertatoms2() is a       */
/*  complete implementation.  linkringinsertatoms() is an optimized wrapper  */
/*  that handles the special case where the entire link ring fits in a       */
/*  single molecule faster, and calls linkringinsertatoms2() otherwise.      */
/*  Profiling suggests that when MOLECULESIZE is 20, linkringinsertatoms()   */
/*  resorts to calling linkringinsertatoms2() only 5.5% of the time.         */
/*                                                                           */
/*  These procedures insert atoms in the REVERSE order they occur in the     */
/*  buffer (to compensate for the fact that linkringtagcompress() writes the */
/*  atoms in reverse order).                                                 */
/*                                                                           */
/*  WARNING:  These procedures uses the input `newatombuffer' not only as a  */
/*  source of atoms to insert, but also as a buffer to shift the following   */
/*  atoms back.  Therefore, the contents of the buffer are trashed.          */
/*                                                                           */
/*  These procedures are meant for internal use by other linkring            */
/*  procedures.                                                              */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from, and that new */
/*    molecules may be allocated from.                                       */
/*  insertposition:  References the position in the link ring to insert the  */
/*    atoms.                                                                 */
/*  insertposition->cule:  Pointer to the molecule.                          */
/*  insertposition->textindex:  The index within the molecule.               */
/*  insertposition->lasttextindex:  Index of the last atom in the molecule   */
/*    thatrepresents a vertex (rather than the "next molecule" tag).         */
/*  insertposition->moleculetag:  Tag for the molecule `position->cule'.     */
/*  insertposition->nextmoleculetag:  Tag for the next molecule in the       */
/*    linked list.  (This field and position->lasttextindex are included so  */
/*    they won't need to be computed a second time.)                         */
/*  numatoms:  The number of atoms to insert.  Must be greater than zero.    */
/*  newatombuffer:  Array of atoms to insert, in reverse order.  This        */
/*    procedure trashes the contents of this buffer.                         */
/*  allocindex:  The allocation index associated with the link ring.         */
/*                                                                           */
/*  Returns the tag of the last molecule in the modified linked list.        */
/*                                                                           */
/*****************************************************************************/

tag linkringinsertatoms2(struct proxipool *pool,
                         struct linkpossmall *insertposition,
                         int numatoms,
                         char *newatombuffer,
                         proxipoolulong allocindex)
{
  molecule cule;
  molecule nextmolecule;
  tag moleculetag;
  tag nextmoleculetag;
  int atomindex;
  int newatomindex;
  int lasttextindex;
  int nextculeindex;
  int bufferatoms;
  int bufferindex;
  int i;
  char nextculeatoms[COMPRESSEDTAGLENGTH];
  char swapatom;
  char nowatom;

  cule = insertposition->cule;
  atomindex = insertposition->textindex;
  lasttextindex = insertposition->lasttextindex;
  moleculetag = insertposition->moleculetag;
  nextmoleculetag = insertposition->nextmoleculetag;
  /* Start at the end of `newatombuffer' and work backward. */
  bufferindex = numatoms - 1;
  /* In the link ring, we are at the start of a compressed tag. */
  swapatom = (char) STOP;

  /* Loop through the linked list of molecules. */
  while (1) {
    /* Loop through the vertex atoms in this molecule. */
    while ((atomindex <= lasttextindex) &&
           ((cule[atomindex] != (char) STOP) || (swapatom >= (char) 0))) {
      /* Swap an atom in the link ring with one in the buffer. */
      swapatom = cule[atomindex];
      cule[atomindex] = newatombuffer[bufferindex];
      newatombuffer[bufferindex] = swapatom;
      atomindex++;
      /* Advance backward through the circular buffer.  This reverses the  */
      /*   order of the input atoms.  The circularity makes it possible to */
      /*   shift the link ring atoms forward through a linked list.        */
      bufferindex = ((bufferindex == 0) ? numatoms : bufferindex) - 1;
    }

    if (nextmoleculetag == STOP) {
      /* We've swapped the last vertex atom in the list into the buffer. */
      break;
    } else {
      /* Find the next molecule. */
      cule = (molecule) proxipooltag2object(pool, nextmoleculetag);
      moleculetag = nextmoleculetag;
      /* Read the tag for the next molecule after that. */
      linkringreadtag(moleculetag, cule, lasttextindex, nextmoleculetag,
                      nowatom, "Internal error in linkringinsertatoms():\n");
      atomindex = 0;
    }
  }

  if (swapatom >= (char) 0) {
    /* The end of the last vertex is missing from the last molecule. */
    printf("Internal error in linkringinsertatoms():\n");
    printf("  Vertex at end of link ring not properly terminated.\n");
    internalerror();
  }

  /* Initialize counter of atoms remaining to append. */
  bufferatoms = numatoms;
  /* While there are too many atoms to fit in one molecule, make molecules. */
  while (atomindex + bufferatoms >= MOLECULESIZE) {
    /* Allocate a new molecule. */
    nextmoleculetag = proxipoolnew(pool, allocindex, (void **) &nextmolecule);
    /* Compress its tag and figure the index to store it at. */
    nextculeindex = MOLECULESIZE -
                    linkringtagcompress(moleculetag, nextmoleculetag,
                                        nextculeatoms);

    /* Is there room for the "next molecule" tag in `cule'? */
    if (atomindex > nextculeindex) {
      /* No; move atoms to the next molecule to make room for the tag. */
      for (newatomindex = 0; newatomindex < atomindex - nextculeindex;
           newatomindex++) {
        nextmolecule[newatomindex] = cule[nextculeindex + newatomindex];
      }
      /* We'll continue writing atoms at this index on the next iteration. */
      atomindex = newatomindex;
    } else {
      /* Fill in the remaining space with atoms from the buffer. */
      while (atomindex < nextculeindex) {
        cule[atomindex] = newatombuffer[bufferindex];
        bufferindex = ((bufferindex == 0) ? numatoms : bufferindex) - 1;
        atomindex++;
        bufferatoms--;
      }
      atomindex = 0;
    }

    /* Copy the "next molecule" tag into the end of `cule'. */
    for (i = nextculeindex; i < MOLECULESIZE; i++) {
      cule[i] = nextculeatoms[i - nextculeindex];
    }
    /* Iterate on the next molecule. */
    moleculetag = nextmoleculetag;
    cule = nextmolecule;
  }

  /* Copy the remaining atoms into the last molecule. */
  while (bufferatoms > 0) {
    cule[atomindex] = newatombuffer[bufferindex];
    bufferindex = ((bufferindex == 0) ? numatoms : bufferindex) - 1;
    bufferatoms--;
    atomindex++;
  }

  /* Write a STOP atom after the last vertex. */
  cule[atomindex] = (char) STOP;
  /* Write a STOP atom for the "next molecule" tag. */
  cule[MOLECULESIZE - 1] = (char) STOP;

  /* Return the tail molecule of the link ring. */
  return moleculetag;
}

/*****************************************************************************/
/*                                                                           */
/*  linkringinsertatoms()   Insert atoms at a specified position in a link   */
/*                          ring (moving the other atoms back to make room). */
/*                                                                           */
/*  See header above linkringinsertatoms2().                                 */
/*                                                                           */
/*****************************************************************************/

tag linkringinsertatoms(struct proxipool *pool,
                        struct linkpossmall *insertposition,
                        int numatoms,
                        char *newatombuffer,
                        proxipoolulong allocindex)
{
  int atomindex;
  char checkatom;

  /* Is the list just one molecule? */
  if (insertposition->nextmoleculetag == STOP) {
    /* Yes.  Find the end of the vertex tags. */
    /* In the link ring, we are at the start of a compressed tag. */
    checkatom = (char) STOP;
    atomindex = insertposition->textindex;
    while ((atomindex <= MOLECULESIZE - 2) &&
           ((insertposition->cule[atomindex] != (char) STOP) ||
            (checkatom >= (char) 0))) {
      checkatom = insertposition->cule[atomindex];
      atomindex++;
    }
    /* Can we fit the new atoms in this molecule? */
    if (atomindex + numatoms < MOLECULESIZE) {
      /* Yes.  Shift atoms to the right to make room for new ones.  Note     */
      /*   that this loop might overwrite the molecule's final atom with the */
      /*   STOP tag, but that's okay, because it's already a STOP tag.       */
      while (atomindex >= insertposition->textindex) {
        insertposition->cule[atomindex + numatoms] =
          insertposition->cule[atomindex];
        atomindex--;
      }
      /* Fill in the new atoms. */
      while (numatoms > 0) {
        atomindex++;
        numatoms--;
        insertposition->cule[atomindex] = newatombuffer[numatoms];
      }
      /* Return the lone molecule's tag. */
      return insertposition->moleculetag;
    }
  }

  /* The updated list does not fit in one molecule.  Do it the general */
  /*   (slow) way.                                                     */
  return linkringinsertatoms2(pool, insertposition, numatoms, newatombuffer,
                              allocindex);
}

/*****************************************************************************/
/*                                                                           */
/*  linkringdeleteatoms()    Delete atoms at a specified position in a link  */
/*  linkringdeleteatoms2()   ring (shifting the following atoms forward).    */
/*                                                                           */
/*  These procedures are interchangeable.  linkringdeleteatoms2() is a       */
/*  complete implementation.  linkringdeleteatoms() is an optimized wrapper  */
/*  that handles the special case where the entire link ring fits in a       */
/*  single molecule faster, and calls linkringdeleteatoms2() otherwise.      */
/*  Profiling suggests that when MOLECULESIZE is 20, linkringdeleteatoms()   */
/*  resorts to calling linkringdeleteatoms2() only 5.0% of the time.         */
/*                                                                           */
/*  Usually, the parameter `position' signifies the first atom to delete.    */
/*  However, if the first atom to delete is at the beginning of a molecule,  */
/*  and that molecule is not the first in the link ring, it's better for     */
/*  `position' to be at the _end_ of the previous molecule, with `textindex' */
/*  past the last vertex atoms in the molecule.  Why?  Because               */
/*  linkringdeleteatoms2() might be able to free the molecule containing the */
/*  first deleted atom--either because all the remaining atoms in the list   */
/*  are deleted, or because the remaining atoms can fit in the previous      */
/*  molecule, overwriting the "next molecule" tag.                           */
/*                                                                           */
/*  linkringdeleteatoms2() deletes atoms from a link ring by having two      */
/*  references traverse through the list, one at a distance behind the       */
/*  other, and by copying atoms from the lead reference to the one following */
/*  it.  To avoid having to decode the "next molecule" tags twice, the lead  */
/*  reference maintains a queue of molecules for use by the following        */
/*  reference.  The queue is an array whose members are reused in circular   */
/*  order, so the link ring can be arbitrarily long.  The size of the queue  */
/*  is fixed, but these procedures are never used to delete more than a      */
/*  small number of atoms, so the lead reference doesn't get too far ahead   */
/*  of the follower.                                                         */
/*                                                                           */
/*  These procedures are meant for internal use by other linkring            */
/*  procedures.  Any external caller needs to be aware that there is a limit */
/*  on the number of atoms that this procedure can delete at once (which can */
/*  be increased by increasing MOLECULEQUEUESIZE).                           */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from.              */
/*  deleteposition:  References the position of the deleted atoms in the     */
/*    link ring.                                                             */
/*  deleteposition->cule:  Pointer to the molecule.                          */
/*  deleteposition->moleculetag:  Tag for the molecule `cule'.  Only needs   */
/*    to be initialized if you are using the return result.  If this is not  */
/*    initialized, the return result might be wrong.                         */
/*  deleteposition->textindex:  The index within the molecule to start       */
/*    deleting atoms from.                                                   */
/*  deleteposition->lasttextindex:  Index of the last atom in the molecule   */
/*    `cule' that represents a vertex (rather than the "next molecule" tag). */
/*  deleteposition->nextmoleculetag:  Tag for the next molecule in the       */
/*    linked list.  (This field and position->lasttextindex are included so  */
/*    they won't need to be computed a second time.)                         */
/*  numatoms:  The number of atoms to delete.                                */
/*                                                                           */
/*  Returns the tag of the last molecule in the modified linked list.        */
/*                                                                           */
/*****************************************************************************/

tag linkringdeleteatoms2(struct proxipool *pool,
                         struct linkpossmall *deleteposition,
                         int numatoms)
{
  struct {
    molecule cule;
    tag culetag;
    int lasttextindex;
  } molequeue[MOLECULEQUEUESIZE];
  molecule leadmolecule;
  molecule followmolecule;
  molecule prevmolecule;
  tag leadnexttag;
  tag leadtag;
  tag returntag;
  int leadindex;
  int followindex;
  int leadlastindex;
  int followlastindex;
  int previndex;
  int leadnextqindex;
  int followcurrentqindex;
  int followprevqindex;
  int followadvanceflag;
  int vertexstartflag;
  int i;
  char nowatom = (char) 0;

  /* Remember the starting position. */
  molequeue[0].cule = deleteposition->cule;
  molequeue[0].culetag = deleteposition->moleculetag;
  molequeue[0].lasttextindex = deleteposition->lasttextindex;
  leadnexttag = deleteposition->nextmoleculetag;

  /* Put the leading and following references at the starting position. */
  leadmolecule = deleteposition->cule;
  followmolecule = deleteposition->cule;
  leadindex = deleteposition->textindex;
  followindex = deleteposition->textindex;
  leadlastindex = deleteposition->lasttextindex;
  followlastindex = deleteposition->lasttextindex;
  /* Keep track of the queue index the lead reference will use next, and the */
  /*   index the follower is using now ('cause that's what's convenient).    */
  leadnextqindex = 1;
  followcurrentqindex = 0;
  /* A flag that indicates whether followcurrentqindex has ever advanced. */
  followadvanceflag = 0;
  /* A flag that indicates we're reading the first atom of a tag. */
  vertexstartflag = 1;

  /* Are we past the last atom in the linked list? */
  if ((leadnexttag == STOP) && (leadindex > leadlastindex)) {
    /* There's nothing here to delete. */
    return deleteposition->moleculetag;
  }

  /* The front reference loops through the molecules of the linked list. */
  do {
    /* Skip this block on the first iteration...unless `deleteposition' is */
    /*   already past all the vertex atoms in its molecule.  On subsequent */
    /*   iterations, this block is always executed.                        */
    if (leadindex > leadlastindex) {
      /* Look up the next molecule (for the lead reference). */
      leadmolecule = (molecule) proxipooltag2object(pool, leadnexttag);
      /* Save it for the follower. */
      molequeue[leadnextqindex].culetag = leadnexttag;
      molequeue[leadnextqindex].cule = leadmolecule;
      leadtag = leadnexttag;
      /* Read the "next molecule" tag. */
      linkringreadtag(leadtag, leadmolecule, leadlastindex, leadnexttag,
                      nowatom, "Internal error in linkringdeleteatoms():\n");
      /* Save the index where the vertex atoms end, for the follower. */
      molequeue[leadnextqindex].lasttextindex = leadlastindex;

      leadindex = 0;
      /* Advance (circularly) the queue index for the next iteration. */
      leadnextqindex = (leadnextqindex + 1 == MOLECULEQUEUESIZE) ?
                       0 : leadnextqindex + 1;
      if (leadnextqindex == followcurrentqindex) {
        /* The leader has just stepped on the follower's data.  The queue */
        /*   isn't large enough to delete this many atoms.                */
        printf("Internal error in linkringdeleteatoms():\n");
        printf("  Asked to delete too many atoms; queue too small.\n");
        printf("  (Increase MOLECULEQUEUESIZE and recompile.)\n");
        internalerror();
      }
    }

    /* Skip up to `numatoms' atoms in this molecule. */
    while ((numatoms > 0) && (leadindex <= leadlastindex)) {
      nowatom = leadmolecule[leadindex];
      if (vertexstartflag && (nowatom == (char) STOP)) {
        /* We've reached the end of the link ring. */
        leadindex = MOLECULESIZE;
#ifdef SELF_CHECK
        if (leadnexttag != STOP) {
          /* Oops.  The link ring ends before the last molecule. */
          printf("Internal error in linkringdeleteatoms():\n");
          printf("  Link ring terminator encountered before last molecule.\n");
          internalerror();
        }
#endif /* SELF_CHECK */
      } else {
        vertexstartflag = nowatom < (char) 0;
        leadindex++;
        numatoms--;
      }
    }

    /* Loop through the atoms in this molecule and copy them from the lead */
    /*   to the follower.  If numatoms > 0, this loop is skipped.          */
    while (leadindex <= leadlastindex) {
      nowatom = leadmolecule[leadindex];
      if (vertexstartflag && (nowatom == (char) STOP)) {
        /* We've reached the end of the link ring. */
        leadindex = MOLECULESIZE;
#ifdef SELF_CHECK
        if (leadnexttag != STOP) {
          /* Oops.  The link ring ends before the last molecule. */
          printf("Internal error in linkringdeleteatoms():\n");
          printf("  Link ring terminator encountered before last molecule.\n");
          internalerror();
        }
#endif /* SELF_CHECK */
      } else {
        /* Is the follower at the end of its molecule? */
        if (followindex > followlastindex) {
          /* Yes.  Advance (circularly) the queue index and molecule. */
          followcurrentqindex =
            (followcurrentqindex + 1 == MOLECULEQUEUESIZE) ?
            0 : followcurrentqindex + 1;
          followmolecule = molequeue[followcurrentqindex].cule;
          followindex = 0;
          followlastindex = molequeue[followcurrentqindex].lasttextindex;
          followadvanceflag = 1;
        }

        /* Copy an atom from the leader. */
        followmolecule[followindex] = nowatom;
        followindex++;

        /* Check the atom for a stop bit. */
        vertexstartflag = nowatom < (char) 0;
        leadindex++;
      }
    }
  } while (leadnexttag != STOP);

  if (nowatom >= (char) 0) {
    /* Oops.  The end of the last vertex is missing from the last molecule. */
    printf("Internal error in linkringdeleteatoms():\n");
    printf("  Vertex at end of link ring not properly terminated.\n");
    internalerror();
  }

  /* The leader has reached the end of the linked list.  The follower might */
  /*   be able to get rid of the molecule it's currently in by moving atoms */
  /*   into the previous molecule, writing over atoms taken by the "next    */
  /*   molecule tag".  Check whether it's possible.  It's only possible if  */
  /*   there is a previous molecule, and that molecule has enough space     */
  /*   currently taken by the "next molecule" tag.                          */
  followprevqindex = (followcurrentqindex == 0) ?
                     MOLECULEQUEUESIZE - 1 : followcurrentqindex - 1;
  if (followadvanceflag &&
      (molequeue[followprevqindex].cule != (molecule) NULL) &&
      (followindex <=
       MOLECULESIZE - 2 - molequeue[followprevqindex].lasttextindex)) {
    prevmolecule = molequeue[followprevqindex].cule;
    previndex = molequeue[followprevqindex].lasttextindex + 1;
    /* Prepare to return the tail molecule. */
    returntag = molequeue[followprevqindex].culetag;
    /* Copy atoms from the follower's molecule to its previous molecule. */
    for (i = 0; i < followindex; i++) {
      prevmolecule[previndex] = followmolecule[i];
      previndex++;
    }
    /* Write a STOP atom after the last vertex. */
    prevmolecule[previndex] = (char) STOP;
    /* Write a STOP atom for the "next molecule" tag. */
    prevmolecule[MOLECULESIZE - 1] = (char) STOP;
  } else {
    /* Prepare to return the tail molecule. */
    returntag = molequeue[followcurrentqindex].culetag;
    /* Write a STOP atom after the last vertex. */
    followmolecule[followindex] = (char) STOP;
    /* Write a STOP atom for the "next molecule" tag. */
    followmolecule[MOLECULESIZE - 1] = (char) STOP;
    /* Start freeing molecules with the next one. */
    followcurrentqindex = (followcurrentqindex + 1 == MOLECULEQUEUESIZE) ?
                          0 : followcurrentqindex + 1;
  }

  /* Loop through the remaining molecules and free them. */
  while (followcurrentqindex != leadnextqindex) {
    proxipoolfree(pool, molequeue[followcurrentqindex].culetag);
    followcurrentqindex = (followcurrentqindex + 1 == MOLECULEQUEUESIZE) ?
                          0 : followcurrentqindex + 1;
  }

  /* Return the tail molecule of the link ring. */
  return returntag;
}

/*****************************************************************************/
/*                                                                           */
/*  linkringdeleteatoms()   Delete atoms at a specified position in a link   */
/*                          ring (shifting the following atoms forward).     */
/*                                                                           */
/*  See header above linkringdeleteatoms2().                                 */
/*                                                                           */
/*****************************************************************************/

tag linkringdeleteatoms(struct proxipool *pool,
                        struct linkpossmall *deleteposition,
                        int numatoms)
{
  int i;

  /* Is the list just one molecule? */
  if (deleteposition->nextmoleculetag == STOP) {
    /* Yes.  Shift atoms to the left to delete `numatoms' atoms. */
    for (i = deleteposition->textindex + numatoms; i < MOLECULESIZE - 1; i++) {
      deleteposition->cule[i - numatoms] = deleteposition->cule[i];
    }
    deleteposition->cule[i - numatoms] = (char) STOP;
    /* Return the lone molecule's tag. */
    return deleteposition->moleculetag;
  } else {
    /* The list does not fit in one molecule.  Do it the general (slow) way. */
    return linkringdeleteatoms2(pool, deleteposition, numatoms);
  }
}

/*****************************************************************************/
/*                                                                           */
/*  linkringrotateatoms()   Swap two contiguous sets of atoms.               */
/*                                                                           */
/*  This is a special-purpose procedure used solely to handle one special    */
/*  case in linkringinsertedge().  If a link ring consists of three or more  */
/*  distinct chains of edges (with three or more ghost vertices filling the  */
/*  gaps), a newly inserted edge might glue together two of those chains--   */
/*  and the chains might not be listed in the right order.  So some of the   */
/*  chains need to be swapped.                                               */
/*                                                                           */
/*  Imagine dividing a link ring into three segments of vertices (including  */
/*  ghost vertices).  One segment begins at position `pos1' and ends with    */
/*  the atom right before position `pos2'.  Another segment begins at `pos2' */
/*  and ends with the atom right before `pos3'.  A third segment begins at   */
/*  `pos3' and (circularly) ends right before `pos1'.  This procedure swaps  */
/*  the first two segments (beginning at `pos1' and `pos2').                 */
/*                                                                           */
/*  WARNING:  It's dangerous to swap two arbitrary segments, because the     */
/*  beginning of the linked list must coincide with the beginning of a       */
/*  compressed vertex tag.  Therefore, the positions `pos1', `pos2', and     */
/*  `pos3' should occur in that order in the linked list, or one of those    */
/*  three should be the very start of the linked list.  Calling this         */
/*  procedure in other circumstances might misalign a compressed tag at the  */
/*  start of the list (though it will swap the atoms as advertised).         */
/*                                                                           */
/*  On return, `pos2' references the first atom of the _moved_ copy of the   */
/*  segment that was originally (but no longer) at `pos1'.  The contents of  */
/*  `pos1' may be trashed, so copy it before calling if you need it.  `pos3' */
/*  is unchanged.                                                            */
/*                                                                           */
/*  It's nearly impossible to do this efficiently without extra buffer       */
/*  space (since the link ring is only singly-linked), and this procedure    */
/*  might temporarily allocate as large an array as it needs.                */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from.              */
/*  linkring:  Tag for the first molecule in the link ring.                  */
/*  pos1:  References the first atom in the first segment to swap.  Contents */
/*    are trashed on return.                                                 */
/*  pos2:  References the first atom in the second segment to swap.  Also    */
/*    demarcates the end of the first segment.  On return, this position     */
/*    references the first atom in the _moved_ segment that was originally   */
/*    the first segment (but now comes second).                              */
/*  pos3:  References the first atom in a third segment, which doesn't move. */
/*    Therefore, `pos3' demarcates the end of the second segment.            */
/*                                                                           */
/*****************************************************************************/

void linkringrotateatoms(struct proxipool *pool,
                         tag linkring,
                         struct linkpossmall *pos1,
                         struct linkpossmall *pos2,
                         struct linkpossmall *pos3)
{
#define STARTBUFFERSIZE 1024

  starlong bufferindex;
  starlong buffersize;
  starlong i;
  int atomindex1, atomindex2, atomindex3;
  int starttag1flag, starttag2flag;
  char firstbuffer[STARTBUFFERSIZE];
  char *buffer;
  char *newbuffer;
  char nowatom;

  /* Start with a buffer in static memory.  We'll allocate a larger one */
  /*   from dynamic memory only if necessary.                           */
  buffer = firstbuffer;
  buffersize = STARTBUFFERSIZE;
  bufferindex = 0;
  /* Move the indices into local variables (hopefully registers). */
  atomindex1 = pos1->textindex;
  atomindex2 = pos2->textindex;
  atomindex3 = pos3->textindex;
  /* Indicate that each position, 1 and 2, is at the start of a compressed */
  /*   vertex tag.                                                         */
  starttag1flag = 1;
  starttag2flag = 1;

  /* Each iteration of this loop advances both positions by one atom. */
  do {
    /* Have we read the last vertex atom in the molecule at position 1? */
    if ((atomindex1 > pos1->lasttextindex) ||
        (starttag1flag && (pos1->cule[atomindex1] == (char) STOP))) {
      /* Yes, we have.  Are there any more molecules after this one? */
      if (pos1->nextmoleculetag == STOP) {
        /* No, there aren't.  Loop back to the start of the linked list. */
        pos1->nextmoleculetag = linkring;
      }
      /* Find the next molecule in the linked list. */
      pos1->cule = (molecule) proxipooltag2object(pool, pos1->nextmoleculetag);
      pos1->moleculetag = pos1->nextmoleculetag;
      /* Read the next molecule's "next molecule" tag. */
      linkringreadtag(pos1->moleculetag, pos1->cule, pos1->lasttextindex,
                      pos1->nextmoleculetag, nowatom,
                      "Internal error in linkringrotateatoms():\n");
      /* Start from the beginning of this molecule. */
      atomindex1 = 0;
    }

    /* Have we read the last vertex atom in the molecule at position 2? */
    if ((atomindex2 > pos2->lasttextindex) ||
        (starttag2flag && (pos2->cule[atomindex2] == (char) STOP))) {
      /* Yes, we have.  Are there any more molecules after this one? */
      if (pos2->nextmoleculetag == STOP) {
        /* No, there aren't.  Loop back to the start of the linked list. */
        pos2->nextmoleculetag = linkring;
      }
      /* Find the next molecule in the linked list. */
      pos2->cule = (molecule) proxipooltag2object(pool, pos2->nextmoleculetag);
      pos2->moleculetag = pos2->nextmoleculetag;
      /* Read the next molecule's "next molecule" tag. */
      linkringreadtag(pos2->moleculetag, pos2->cule, pos2->lasttextindex,
                      pos2->nextmoleculetag, nowatom,
                      "Internal error in linkringrotateatoms():\n");
      /* Start from the beginning of this molecule. */
      atomindex2 = 0;

      /* Exit the loop when position 2 reaches position 3. */
      if ((pos2->cule == pos3->cule) && (atomindex2 == atomindex3)) {
        break;
      }
    }

    /* There's no telling at the start how large a buffer we need, so we */
    /*   may need to resize it.                                          */
    if (bufferindex >= buffersize) {
      newbuffer = (char *) starmalloc((size_t) (buffersize * 3));
      for (i = 0; i < buffersize; i++) {
        newbuffer[i] = buffer[i];
      }
      /* The first buffer is in static memory; only free subsequent buffers. */
      if (buffer != firstbuffer) {
        starfree(buffer);
      }
      buffer = newbuffer;
      buffersize *= 3;
    }

    /* Copy atoms from position 1 to the buffer. */
    nowatom = pos1->cule[atomindex1];
    buffer[bufferindex] = nowatom;
    /* Will we be starting a new tag at position 1?  Check for a stop bit. */
    starttag1flag = nowatom < (char) 0;
    /* Copy atoms from position 2 to position 1. */
    nowatom = pos2->cule[atomindex2];
    pos1->cule[atomindex1] = nowatom;
    /* Will we be starting a new tag at position 2? */
    starttag2flag = nowatom < (char) 0;
    /* Advance all the positions. */
    bufferindex++;
    atomindex1++;
    atomindex2++;

    /* Exit the loop when position 2 reaches position 3. */
  } while ((pos2->cule != pos3->cule) || (atomindex2 != atomindex3));

  /* Now we know how many atoms are in the second segment.  Set up the */
  /*   buffer to be a circular buffer of that length.                  */
  buffersize = bufferindex;
  bufferindex = 0;

  /* Store the position of the (now) second of the two swapped segments, to */
  /*   return to the caller.                                                */
  *pos2 = *pos1;
  pos2->textindex = atomindex1;

  /* Position 1 continues to loop through atoms, swapping them with atoms   */
  /*   in the circular buffer, until it reaches position 3.  The circular   */
  /*   buffer makes it possible to move all the atoms in the first segment  */
  /*   back by a number of atoms equal to the length of the second segment, */
  /*   without knowing how long the first segment is.                       */
  do {
    /* Have we read the last vertex atom in the molecule at position 1? */
    if ((atomindex1 > pos1->lasttextindex) ||
        (starttag1flag && (pos1->cule[atomindex1] == (char) STOP))) {
      /* Yes, we have.  Are there any more molecules after this one? */
      if (pos1->nextmoleculetag == STOP) {
        /* No, there aren't.  Loop back to the start of the linked list. */
        pos1->nextmoleculetag = linkring;
      }
      /* Find the next molecule in the linked list. */
      pos1->cule = (molecule) proxipooltag2object(pool, pos1->nextmoleculetag);
      pos1->moleculetag = pos1->nextmoleculetag;
      /* Read the next molecule's "next molecule" tag. */
      linkringreadtag(pos1->moleculetag, pos1->cule, pos1->lasttextindex,
                      pos1->nextmoleculetag, nowatom,
                      "Internal error in linkringrotateatoms():\n");
      /* Start from the beginning of this molecule. */
      atomindex1 = 0;

      /* Exit the loop when position 1 reaches position 3. */
      if ((pos1->cule == pos3->cule) && (atomindex1 == atomindex3)) {
        break;
      }
    }

    /* Swap atoms between position 1 and the buffer. */
    nowatom = pos1->cule[atomindex1];
    pos1->cule[atomindex1] = buffer[bufferindex];
    buffer[bufferindex] = nowatom;
    /* Will we be starting a new tag?  Check for a stop bit. */
    starttag1flag = nowatom < (char) 0;
    /* Advance the positions. */
    bufferindex = (bufferindex + 1 >= buffersize) ? 0 : bufferindex + 1;
    atomindex1++;
    /* Exit the loop when position 1 reaches position 3. */
  } while ((pos1->cule != pos3->cule) || (atomindex1 != atomindex3));

  /* If the buffer was allocated dynamically, free it. */
  if (buffer != firstbuffer) {
    starfree(buffer);
  }
}

/*****************************************************************************/
/*                                                                           */
/*  linkringinsertedge()   Insert an edge into a link ring.                  */
/*                                                                           */
/*  If this link ring is the link of an edge, you are actually inserting a   */
/*  tetrahedron (from the edge's point of view--you may need to inform the   */
/*  tetrahedron's other edges as well.)  If this link ring is the link of a  */
/*  vertex, you are actually inserting a triangle (from the vertex's point   */
/*  of view).                                                                */
/*                                                                           */
/*  The new edge is `endpoint1'-`endpoint2', with `endpoint2' immediately    */
/*  following (counterclockwise from--unless you're using the reverse        */
/*  orientation everywhere, as these procedures can't tell the difference)   */
/*  `endpoint1'.  The order in which the two endpoints are given matters--it */
/*  must match the desired orientation of the link ring.  It is possible to  */
/*  have a link ring with just two edges--say, 1-2 and 2-1.                  */
/*                                                                           */
/*  If both vertices of the new edge are already present, this procedure     */
/*  can glue two chains together, or close a single chain (making the link   */
/*  into a true ring), if it's appropriate to do so.                         */
/*                                                                           */
/*  This procedure will return 0 and leave the link ring unchanged if any of */
/*  the following is true.                                                   */
/*                                                                           */
/*  - There is already an edge immediately following `endpoint1'.  (That is, */
/*    `endpoint1' is in the list and is not followed by a ghost vertex.)     */
/*  - There is already an edge immediately preceding `endpoint2'.  (That is, */
/*    `endpoint2' is in the list and is not preceded by a ghost vertex.)     */
/*  - The link ring is truly a ring, with no space to insert a new edge      */
/*    (i.e. no ghost vertex).                                                */
/*  - The link ring currently consists of two or more chains, and the        */
/*    introduction of the new edge will glue one of them into a ring.  It's  */
/*    not topologically possible to have a link with a ring AND a chain.     */
/*                                                                           */
/*  WARNING:  This procedure will not usually work if there is more than one */
/*  copy of `endpoint1', or more than one copy of `endpoint2', in the ring.  */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from, and that new */
/*    molecules may be allocated from.                                       */
/*  linkring:  Tag for the first molecule in the link ring.                  */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  endpoint1:  The tag of the new edge's first vertex.                      */
/*  endpoint2:  The tag of the new edge's second vertex.                     */
/*                                                                           */
/*  Returns one of the following values.                                     */
/*    0:  If the edge cannot be inserted, and the link ring is unchanged.    */
/*    1:  If `endpoint1' was inserted, and `endpoint2' was already present.  */
/*    2:  If `endpoint2' was inserted, and `endpoint1' was already present.  */
/*    3:  If neither vertex was present, and both were inserted.  (In this   */
/*        case, a ghost vertex is inserted as well to prevent the new edge   */
/*        from being connected to any other vertex.)                         */
/*    4:  If both `endpoint1' and `endpoint2' were already present in the    */
/*        link, and merely needed to be connected by an edge (which is       */
/*        accomplished by deleting the ghost vertex between the two          */
/*        endpoints).                                                        */
/*                                                                           */
/*****************************************************************************/

int linkringinsertedge(struct proxipool *pool,
                       tag linkring,
                       tag groundtag,
                       tag endpoint1,
                       tag endpoint2)
{
  struct linkpossmall position;
  struct linkpossmall pt2position;
  struct linkpossmall ghostposition;
  struct linkpossmall ghostafter1position;
  struct linkpossmall afterghostafter2position;
  molecule cule;
  tag nextmoleculetag;
  tag moleculetag;
  int atomindex;
  int lasttextindex;
  int numatoms;
  char newvertexatoms[2 * COMPRESSEDTAGLENGTH + 1];
  char nowatom;

  /* There is no "previous" vertex we've visited yet. */
  tag firstvertextag = STOP;
  tag prevvertextag = STOP;
  tag prevprevvertextag = STOP;
  tag vertextag = 0;
  int vertexatoms = 0;
  /* Set to 1 during the first iteration of the "do" loop. */
  int firstflag = 1;
  /* The following flags indicate whether `endpoint1', `endpoint2', or */
  /*   a ghost vertex have been visited in the linked list yet.        */
  int oneflag = 0;
  int twoflag = 0;
  int ghostflag = 0;
  /* Set if `endpoint2' is one of the first two vertices in the linked list. */
  int early2flag = 0;
  /* Set if `endpoint2' has been visited, but not `endpoint1' after it. */
  int twonot1flag = 0;
  /* Set if a ghost vertex has been visited, but not `endpoint2' after it. */
  int ghostnot2flag = 0;
  /* Set if at least one ghost vertex comes after `endpoint2' but before */
  /*   `endpoint1' in the ring (taking into account that it loops).      */
  int ghostbetween21flag = 0;
  /* Set if `endpoint1' appears after `endpoint2' in the linked list. */
  int oneafter2flag = 0;
  /* Set if a ghost vertex appears after `endpoint2' in the linked list. */
  int ghostafter2flag = 0;

  if ((linkring >= STOP) || (endpoint1 >= STOP) || (endpoint2 >= STOP)) {
    /* Invalid parameters. */
    return 0;
  }

  /* Start at the first molecule. */
  nextmoleculetag = linkring;

  /* Loop through the linked list of molecules. */
  do {
    /* Convert the molecule's tag to a pointer. */
    cule = (molecule) proxipooltag2object(pool, nextmoleculetag);
    moleculetag = nextmoleculetag;
    /* Read the "next molecule" tag. */
    linkringreadtag(moleculetag, cule, lasttextindex, nextmoleculetag, nowatom,
                    "Internal error in linkringinsertedge():\n");
    if (firstflag) {
      /* Position to insert or delete atoms at the beginning of the list. */
      position.cule = cule;
      position.moleculetag = moleculetag;
      position.textindex = 0;
      position.lasttextindex = lasttextindex;
      position.nextmoleculetag = nextmoleculetag;
      firstflag = 0;
    }

    atomindex = 0;
    /* Loop through the atoms, stopping at the "next molecule" tag. */
    while (atomindex <= lasttextindex) {
      nowatom = cule[atomindex];
      /* Append the atom to the vertex tag. */
      vertextag = (vertextag << 7) + (nowatom & (char) 127);
      vertexatoms++;
      atomindex++;

      /* Is this the last atom in the compressed tag? */
      if (nowatom < (char) 0) {
        /* Yes; we have an uncompressed tag now.  What tag is it? */
        if ((nowatom == (char) STOP) && (vertexatoms == 1)) {
          /* STOP tag.  Exit the inner loop early; go on to next molecule. */
          break;
        } else if ((nowatom == (char) GHOSTVERTEX) && (vertexatoms == 1)) {
          /* Ghost vertex. */
          vertextag = GHOSTVERTEX;
          ghostflag = 1;
          if (twoflag) {
            /* The beginning/end of the linked list does not fall between */
            /*   `endpoint2' and the following ghost.                     */
            ghostafter2flag = 1;
          }
          if (twonot1flag) {
            /* Because `endpoint2' has been visited, and `endpoint1' didn't */
            /*   follow it, this ghost vertex appears after `endpoint2' and */
            /*   before `endpoint1' in the link ring...IF `endpoint1' is in */
            /*   the link at all.  (If not, this won't hurt.)               */
            ghostbetween21flag = 1;
          }
          /* Remember the ghost's position in case we need to insert a */
          /*   vertex here or delete the ghost.                        */
          ghostposition = position;
          if (prevvertextag == endpoint1) {
            ghostafter1position = position;
          }
          if (!ghostnot2flag) {
            /* Remember the position after the ghost, in case we need to */
            /*   rotate the atoms in the link ring.  Note that if        */
            /*   `endpoint2' isn't in the link ring, this branch might   */
            /*   execute, but it won't matter.                           */
            afterghostafter2position.cule = cule;
            afterghostafter2position.textindex = atomindex;
            afterghostafter2position.lasttextindex = lasttextindex;
            afterghostafter2position.moleculetag = moleculetag;
            afterghostafter2position.nextmoleculetag = nextmoleculetag;
          }
          ghostnot2flag = 1;
        } else {
          /* The tag is neither a STOP tag nor a ghost vertex. */
          if (prevvertextag == endpoint1) {
            /* `endpoint1' does not have a ghost vertex after it, so it is */
            /*   not possible to insert an (ordered) edge 1-2.             */
            return 0;
          }

          /* Use the ground tag to supply the high-order bits. */
          vertextag += (groundtag >> (7 * vertexatoms)) << (7 * vertexatoms);

          if (vertextag == endpoint1) {
            oneflag = 1;
            twonot1flag = 0;
            if (ghostnot2flag) {
              /* Because a ghost vertex has been visited, and `endpoint2' */
              /*   didn't follow it, that ghost vertex appears after      */
              /*   `endpoint2' and before `endpoint1' in the link ring... */
              /*   IF `endpoint2' is in the link at all.  (If not, this   */
              /*   won't hurt.)                                           */
              ghostbetween21flag = 1;
            }
            if (twoflag) {
              oneafter2flag = 1;
            }
          } else if (vertextag == endpoint2) {
            if ((prevvertextag != GHOSTVERTEX) && (prevvertextag != STOP)) {
              /* `endpoint2' does not have a ghost vertex before it, so it */
              /*   is not possible to insert an (ordered) edge 1-2.        */
              return 0;
            }
            if (prevprevvertextag == endpoint1) {
              /* `endpoint1' is immediately followed by a ghost vertex, then */
              /*   `endpoint2', so just delete the ghost from the middle.    */
              linkringdeleteatoms(pool, &ghostposition, 1);
              return 4;
            }

            if (prevprevvertextag == STOP) {
              /* `endpoint2' is one of the first two vertices in the list. */
              /*   Remember this in case `endpoint1' is the last.          */
              early2flag = 1;
            }
            twoflag = 1;
            twonot1flag = 1;
            ghostnot2flag = 0;
            /* Remember `endpoint2's position in case we need to insert */
            /*   `endpoint1' in front of it.                            */
            pt2position = position;
          }
        }

        if (prevvertextag == STOP) {
          /* This is the first vertex.  Remember it. */
          firstvertextag = vertextag;
        }

        /* Remember `vertextag' for the next two iterations. */
        prevprevvertextag = prevvertextag;
        prevvertextag = vertextag;
        /* Prepare to read another tag. */
        vertextag = 0;
        vertexatoms = 0;

        /* Store the position of the beginning of the next compressed tag,   */
        /*   in case we realize we need it once we reach the end of the tag. */
        position.cule = cule;
        position.textindex = atomindex;
        position.lasttextindex = lasttextindex;
        position.moleculetag = moleculetag;
        position.nextmoleculetag = nextmoleculetag;
      }
    }
  } while (nextmoleculetag != STOP);

  if (nowatom >= (char) 0) {
    /* Oops.  The end of the last vertex is missing from the last molecule. */
    printf("Internal error in linkringinsertedge():\n");
    printf("  Vertex at end of link ring not properly terminated.\n");
    internalerror();
  }

  if (prevvertextag == endpoint1) {
    /* The last vertex in the linked list is `endpoint1'. */
    if (firstvertextag != GHOSTVERTEX) {
      /* `endpoint1' does not have a ghost vertex after it, so it is */
      /*   not possible to insert an (ordered) edge 1-2.             */
      return 0;
    } else if (!twoflag) {
      /* `endpoint2' is not in the list, so insert it right after */
      /*   `endpoint1' (at the very end of the linked list).      */
      numatoms = linkringtagcompress(groundtag, endpoint2, newvertexatoms);
      linkringinsertatoms(pool, &position, numatoms, newvertexatoms,
                          proxipooltag2allocindex(pool, linkring));
      return 2;
    } else {
      /* The ghost following `endpoint1` is at the beginning of the list. */
      ghostafter1position.moleculetag = linkring;
      ghostafter1position.cule = (molecule) proxipooltag2object(pool,
                                                                linkring);
      ghostafter1position.textindex = 0;
      /* Read the "next molecule" tag. */
      linkringreadtag(linkring, ghostafter1position.cule,
                      ghostafter1position.lasttextindex,
                      ghostafter1position.nextmoleculetag,
                      nowatom, "Internal error in linkringinsertedge():\n");
      if (early2flag) {
        /* `endpoint2' must occur second in the linked list, with a ghost   */
        /*   vertex before it, and `endpoint1' at the end of the list (thus */
        /*   before the ghost in the link ring).  Delete the ghost vertex.  */
        linkringdeleteatoms(pool, &ghostafter1position, 1);
        return 4;
      }
      /* If execution reaches this point, we either need to rotate a portion */
      /*   of the link ring, or decide that inserting the edge is            */
      /*   impossible.  Code for doing these appears further down.           */
    }
  } else if (firstvertextag == endpoint2) {
    /* The first vertex in the linked list is `endpoint2'. */
    if (prevvertextag != GHOSTVERTEX) {
      /* `endpoint2' (at the beginning of the linked list) does not have a   */
      /*   ghost vertex before it in the link ring (at the end of the list), */
      /*   so it is not possible to insert an (ordered) edge 1-2.            */
      return 0;
    } else if (prevprevvertextag == endpoint1) {
      /* The linked list ends with `endpoint1' (second to last) and a ghost */
      /*   vertex (last), and begins with `endpoint2'.  Delete the ghost.   */
      linkringdeleteatoms(pool, &ghostposition, 1);
      return 4;
    } else if (!oneflag) {
      /* `endpoint1' is not in the list, so insert it at the very end of the */
      /*   linked list, putting it right before `endpoint2' in the ring.     */
      numatoms = linkringtagcompress(groundtag, endpoint1, newvertexatoms);
      linkringinsertatoms(pool, &position, numatoms, newvertexatoms,
                          proxipooltag2allocindex(pool, linkring));
      return 1;
    }
    /* If execution reaches this point, we either need to rotate a portion */
    /*   of the link ring, or decide that inserting the edge is            */
    /*   impossible.  Code for doing these appears soon.                   */
  }

  if (oneflag) {
    if (twoflag) {
      if (ghostbetween21flag) {
        /* Here is the yuckiest situation.  There is a ghost vertex after    */
        /*   `endpoint1', and a ghost vertex before `endpoint2', but they    */
        /*   are not the same ghost vertex.  There is a third ghost vertex   */
        /*   following `endpoint2' and preceding `endpoint1'.  Therefore,    */
        /*   the link ring is composed of three or more connected chains of  */
        /*   edges, and we need to reorder these chains to get `endpoint1'   */
        /*   and `endpoint2' connected to each other.  There's a procedure   */
        /*   written just for this purpose.                                  */
        /*                                                                   */
        /* Imagine dividing the link ring into three segments of vertices    */
        /*   (including ghost vertices).  Segment 2 begins with `endpoint2'  */
        /*   and ends with the first ghost vertex following it.  Segment 1   */
        /*   begins right after that ghost vertex, and ends at `endpoint1'.  */
        /*   Segment 0 begins with the next vertex, a ghost vertex, and ends */
        /*   with the vertex right before `endpoint2', also a ghost vertex.  */
        /*   We want to swap two of these segments, thereby creating the     */
        /*   edge 1-2.  The swap also puts two ghost vertices together, at   */
        /*   the start of Segment 0 and the end of Segment 2, so we then     */
        /*   delete one of those two ghost vertices.                         */
        /*                                                                   */
        /* However, it's dangerous to swap two arbitrary segments, because   */
        /*   the beginning of the link ring must coincide with the beginning */
        /*   of a vertex.  Therefore, we identify two segments that are safe */
        /*   to swap (don't have the beginning/end of the link ring inside   */
        /*   them), and swap those.                                          */
        if (oneafter2flag) {
          /* It is safe to swap Segments 2 and 1. */
          position = ghostafter1position;
          linkringrotateatoms(pool, linkring, &pt2position,
                              &afterghostafter2position, &ghostafter1position);
        } else if (ghostafter2flag) {
          /* `endpoint1' precedes `endpoint2' in the linked list, and a */
          /*    ghost vertex follows `endpoint2', so it is safe to swap */
          /*    Segments 0 and 2.                                       */
          linkringrotateatoms(pool, linkring, &ghostafter1position,
                              &pt2position, &afterghostafter2position);
          /* When the above procedure returns, `pt2position' is the new */
          /*   position of Segment 0.                                   */
          position = pt2position;
        } else {
          /* Segment 2 overlaps the beginning/end of the link ring, so it is */
          /*   safe to swap Segments 1 and 0.                                */
          position = afterghostafter2position;
          linkringrotateatoms(pool, linkring, &afterghostafter2position,
                              &ghostafter1position, &pt2position);
        }

        /*   The swap puts two ghost vertices together, at the end of      */
        /*   Segment 2 and the start of Segment 0.  Delete the second one. */
        linkringdeleteatoms(pool, &position, 1);
        return 4;
      } else {
        /* There is a ghost vertex after `endpoint1', and a ghost vertex     */
        /*   before `endpoint2', but they are not the same ghost vertex.     */
        /*   There is no ghost vertex following `endpoint2' and preceding    */
        /*   `endpoint1', so the two endpoints are ends of the same chain.   */
        /*   If we create an edge 1-2, it will close that chain into a ring. */
        /*   However, there's at least one other chain, and it's not         */
        /*   topologically possible to have a link with a ring AND a chain.  */
        return 0;
      }
    } else {
      /* `endpoint2' is not in the list, so insert it right after */
      /*   `endpoint1'.                                           */
      numatoms = linkringtagcompress(groundtag, endpoint2, newvertexatoms);
      linkringinsertatoms(pool, &ghostafter1position, numatoms, newvertexatoms,
                          proxipooltag2allocindex(pool, linkring));
      return 2;
    }
  } else {
    if (twoflag) {
      /* `endpoint1' is not in the list, so insert it right before */
      /*   `endpoint2'.                                            */
      numatoms = linkringtagcompress(groundtag, endpoint1, newvertexatoms);
      linkringinsertatoms(pool, &pt2position, numatoms, newvertexatoms,
                          proxipooltag2allocindex(pool, linkring));
      return 1;
    } else {
      /* Neither `endpoint1' nor `endpoint2' are in the list. */
      if (ghostflag || (prevvertextag == STOP)) {
        /* Insert a ghost vertex, followed by `endpoint1', followed by    */
        /*   `endpoint2'.  Because linkringtagcompress() writes the atoms */
        /*   backward, and linkringinsertatoms() reverses them back to    */
        /*   forward, write the sequence 2-1-ghost into the buffer.       */
        numatoms = linkringtagcompress(groundtag, endpoint2,
                                       newvertexatoms);
        numatoms += linkringtagcompress(groundtag, endpoint1,
                                        &newvertexatoms[numatoms]);
        newvertexatoms[numatoms] = (char) GHOSTVERTEX;
        if (ghostflag) {
          /* Insert them in front of a ghost vertex. */
          linkringinsertatoms(pool, &ghostposition, numatoms + 1,
                              newvertexatoms,
                              proxipooltag2allocindex(pool, linkring));
        } else {
          /* The link ring is empty.  Insert the three vertices. */
          linkringinsertatoms(pool, &position, numatoms + 1, newvertexatoms,
                              proxipooltag2allocindex(pool, linkring));
        }
        return 3;
      } else {
        /* The link ring is really a ring, so there's no gap to put a new */
        /*   edge into.                                                   */
        return 0;
      }
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  linkringdeleteedge()   Delete an edge from a link ring.                  */
/*                                                                           */
/*  This procedure also deletes any endpoint of the edge that is not an      */
/*  endpoint of another edge.  Therefore, it cannot be used to create a      */
/*  single dangling vertex with no edge.  (You can accomplish that by using  */
/*  linkringdeletevertex() to whittle a chain down to one vertex, or by      */
/*  using linkringinsertvertex() to insert a ghost vertex.)                  */
/*                                                                           */
/*  The order in which the two endpoints are given matters--it must match    */
/*  the edge's orientation in the link ring.  It is possible to have a link  */
/*  ring with just two edges--say, 1-2 and 2-1.  In this case, the order of  */
/*  the endpoints determines which of the two edges is deleted.              */
/*                                                                           */
/*  WARNING:  This procedure will not usually work if there is more than one */
/*  copy of `endpoint1', or more than one copy of `endpoint2', in the ring.  */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from, and that new */
/*    molecules may be allocated from.                                       */
/*  linkring:  Tag for the first molecule in the link ring.                  */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  endpoint1:  The tag of the deleted edge's first vertex.                  */
/*  endpoint2:  The tag of the deleted edge's second vertex.                 */
/*                                                                           */
/*  Returns one of the following values.                                     */
/*    -1:  If the link ring is empty on entry (so it is not changed).        */
/*     0:  If the edge is not present, and the link ring is unchanged (but   */
/*         not empty).                                                       */
/*     1:  If `endpoint1' was deleted, and `endpoint2' survives because it   */
/*         is an endpoint of another edge.                                   */
/*     2:  If `endpoint2' was deleted, and `endpoint1' survives.             */
/*     3:  If both vertices are deleted, but some other vertex survives.     */
/*         (In this case, a ghost vertex is deleted as well, to prevent      */
/*         having two adjacent ghost vertices.)                              */
/*     7:  If both vertices are deleted, and the link ring is now empty.     */
/*         (A ghost vertex is deleted as well.)                              */
/*     8:  If the edge is deleted, but both vertices survive.  (In this      */
/*         case, a ghost vertex is inserted between them.)                   */
/*                                                                           */
/*    Hence, a positive return value implies that the edge was deleted, and  */
/*    the 4's bit signifies whether the link ring is empty on return.  If    */
/*    the result is not zero, the 1's bit signifies that `endpoint1' is no   */
/*    longer in the link ring (or never was), and the 2's bit signifies that */
/*    `endpoint2' is not in the link ring on return.  (If the result is      */
/*    zero, this procedure doesn't check whether the endpoints are present.) */
/*                                                                           */
/*****************************************************************************/

int linkringdeleteedge(struct proxipool *pool,
                       tag linkring,
                       tag groundtag,
                       tag endpoint1,
                       tag endpoint2)
{
  struct linkpossmall position;
  struct linkpossmall pt1position;
  struct linkpossmall pt2position;
  struct linkpossmall ghostposition;
  molecule cule;
  tag nextmoleculetag;
  tag moleculetag;
  int atomindex;
  int lasttextindex;
  char ghostatom[1];
  char nowatom;

  /* There is no "previous" vertex we've visited yet. */
  tag firstvertextag = STOP;
  tag prevvertextag = STOP;
  tag vertextag = 0;
  long vertexcount = 0;
  int vertexatoms = 0;
  int end1atoms = 0;
  int end2atoms = 0;
  /* Set to 1 during the first iteration of the "do" loop. */
  int firstflag = 1;
  /* Set if there is a ghost vertex immediately before `endpoint1'. */
  int ghostbefore1flag = 0;
  /* Set if there is a ghost vertex immediately after `endpoint2'. */
  int ghostafter2flag = 0;
  int earlystopflag = 0;

  if ((linkring >= STOP) || (endpoint1 >= STOP) || (endpoint2 >= STOP)) {
    /* Invalid parameters. */
    return 0;
  }

  /* Start at the first molecule. */
  nextmoleculetag = linkring;

  /* Loop through the linked list of molecules. */
  do {
    /* Convert the molecule's tag to a pointer. */
    cule = (molecule) proxipooltag2object(pool, nextmoleculetag);
    moleculetag = nextmoleculetag;
    /* Read the "next molecule" tag. */
    linkringreadtag(moleculetag, cule, lasttextindex, nextmoleculetag, nowatom,
                    "Internal error in linkringdeleteedge():\n");
    if (firstflag) {
      /* Position to insert or delete atoms at the beginning of the list. */
      position.cule = cule;
      position.moleculetag = moleculetag;
      position.textindex = 0;
      position.lasttextindex = lasttextindex;
      position.nextmoleculetag = nextmoleculetag;
      firstflag = 0;
    }

    atomindex = 0;
    /* Loop through the atoms, stopping at the "next molecule" tag. */
    while (atomindex <= lasttextindex) {
      nowatom = cule[atomindex];
      /* Append the atom to the vertex tag. */
      vertextag = (vertextag << 7) + (nowatom & (char) 127);
      vertexatoms++;
      atomindex++;

      /* Is this the last atom in the compressed tag? */
      if (nowatom < (char) 0) {
        /* Yes; we have an uncompressed tag now.  What tag is it? */
        if ((nowatom == (char) STOP) && (vertexatoms == 1)) {
          /* STOP tag.  Exit the inner loop early; go on to next molecule. */
          break;
        } else if ((nowatom == (char) GHOSTVERTEX) && (vertexatoms == 1)) {
          vertextag = GHOSTVERTEX;
          /* Remember this position in case we need to delete vertices here. */
          ghostposition = position;
          if (prevvertextag == endpoint2) {
            /* There's a ghost vertex immediately after `endpoint2'. */
            ghostafter2flag = 1;
          }
        } else {
          /* Use the ground tag to supply the high-order bits. */
          vertextag += (groundtag >> (7 * vertexatoms)) << (7 * vertexatoms);

          if (vertextag == endpoint2) {
            /* Remember this position in case we need to insert a ghost */
            /*   vertex here or delete `endpoint2'.                     */
            pt2position = position;
            end2atoms = vertexatoms;
          } else if (vertextag == endpoint1) {
            /* Remember this position in case we need to delete vertices */
            /*   here.                                                   */
            pt1position = position;
            end1atoms = vertexatoms;
            if (prevvertextag == GHOSTVERTEX) {
              /* There's a ghost vertex immediately before `endpoint1'. */
              ghostbefore1flag = 1;
            }
          }
        }

        vertexcount++;
        if (vertexcount == 1) {
          /* This is the first vertex.  Remember it. */
          firstvertextag = vertextag;
        } else if ((prevvertextag == endpoint1) ^ (vertextag == endpoint2)) {
          /* Either `endpoint1' occurs without `endpoint2' following it, or */
          /*   `endpoint2' occurs without `endpoint1' preceding it, so the  */
          /*   edge we seek to delete doesn't exist.                        */
          return 0;
        } else if ((prevvertextag == endpoint2) && (vertexcount > 3)) {
          /* If execution reaches here, the edge 1-2 does appear in the link */
          /*   ring, and we've collected enough information to determine     */
          /*   whether thre are ghost vertices immediately preceding and     */
          /*   following it.  Exit both loops early.                         */
          earlystopflag = 1;
          nextmoleculetag = STOP;
          break;
        }

        /* Remember this tag during the next iteration. */
        prevvertextag = vertextag;
        /* Prepare to read another tag. */
        vertextag = 0;
        vertexatoms = 0;

        /* Store the position of the beginning of the next compressed tag,   */
        /*   in case we realize we need it once we reach the end of the tag. */
        position.cule = cule;
        position.textindex = atomindex;
        position.lasttextindex = lasttextindex;
        position.moleculetag = moleculetag;
        position.nextmoleculetag = nextmoleculetag;
      }
    }
  } while (nextmoleculetag != STOP);

  if (nowatom >= (char) 0) {
    /* Oops.  The end of the last vertex is missing from the last molecule. */
    printf("Internal error in linkringdeleteedge():\n");
    printf("  Vertex at end of link ring not properly terminated.\n");
    internalerror();
  }

  if (!earlystopflag) {
    if (vertexcount < 2) {
      /* There are fewer than two vertices in the link ring, hence no edge. */
      return (vertexcount == 0) ? -1 : 0;
    } else if (firstvertextag == endpoint1) {
      /* Check if the last vertex in the linked list is a ghost vertex, as */
      /*   it immediately precedes `endpoint1' in the link ring.           */
      ghostbefore1flag = prevvertextag == GHOSTVERTEX;
    } else if (prevvertextag == endpoint2) {
      /* Check if the first vertex in the linked list is a ghost vertex, as */
      /*   it immediately follows `endpoint2' in the link ring.             */
      ghostafter2flag = firstvertextag == GHOSTVERTEX;
    } else if ((prevvertextag != endpoint1) || (firstvertextag != endpoint2)) {
      /* The edge 1-2 is not in the link ring. */
      return 0;
    }
  }

  /* If execution reaches this point, the edge 1-2 is in the link ring. */
  if (ghostafter2flag) {
    if (ghostbefore1flag) {
      /* There are ghost vertices immediately before and after the edge 1-2, */
      /*   and you can't have two ghosts in a row, so one of the ghosts must */
      /*   be deleted along with `endpoint1' and `endpoint2'.                */
      if (vertexcount <= 3) {
        /* Just edge 1-2 and a ghost in the ring.  Empty the link ring. */
        linkringrestart(pool, linkring);
        return 7;
      } else if (earlystopflag) {
        /* Delete the contiguous sequence 1-2-ghost. */
        linkringdeleteatoms(pool, &pt1position, end1atoms + end2atoms + 1);
      } else if (prevvertextag == endpoint1) {
        /* Delete the sequence ghost-1 from the end of the linked list. */
        linkringdeleteatoms(pool, &ghostposition, end1atoms + 1);
        /* The deletion above may have changed the "next molecule" tag */
        /*   stored in the molecule at `pt2position' to STOP.          */
        if (pt2position.cule[MOLECULESIZE - 1] == (char) STOP) {
          pt2position.nextmoleculetag = STOP;
          pt2position.lasttextindex = MOLECULESIZE - 2;
        }
        /* Delete `endpoint2' from the beginning of the list. */
        linkringdeleteatoms(pool, &pt2position, end2atoms);
      } else if (prevvertextag == endpoint2) {
        /* Delete the sequence ghost-1-2 from the end of the linked list. */
        linkringdeleteatoms(pool, &ghostposition, end1atoms + end2atoms + 1);
      } else {
        /* Delete a ghost vertex from the end of the linked list. */
        linkringdeleteatoms(pool, &ghostposition, 1);
        /* The deletion above may have changed the "next molecule" tag */
        /*   stored in the molecule at `pt1position' to STOP.          */
        if (pt1position.cule[MOLECULESIZE - 1] == (char) STOP) {
          pt1position.nextmoleculetag = STOP;
          pt1position.lasttextindex = MOLECULESIZE - 2;
        }
        /* Delete the sequence 1-2 from the beginning of the list. */
        linkringdeleteatoms(pool, &pt1position, end1atoms + end2atoms);
      }
      return 3;
    } else {
      /* There is a ghost vertex immediately after `endpoint2', but not   */
      /*   before `endpoint1', so `endpoint1' is shared with another edge */
      /*   and will survive.  Delete only `endpoint2'.                    */
      linkringdeleteatoms(pool, &pt2position, end2atoms);
      return 2;
    }
  } else {
    if (ghostbefore1flag) {
      /* There is a ghost vertex immediately before `endpoint1', but not */
      /*   after `endpoint2', so `endpoint2' is shared with another edge */
      /*   and will survive.  Delete only `endpoint1'.                   */
      linkringdeleteatoms(pool, &pt1position, end1atoms);
      return 1;
    } else {
      /* There is no ghost vertex immediately before or after edge 1-2, so   */
      /*   both vertices survive.  Insert a ghost vertex between `endpoint1' */
      /*   and `endpoint2'.                                                  */
      ghostatom[0] = (char) GHOSTVERTEX;
      if (prevvertextag == endpoint1) {
        /* Put the ghost vertex at the end of the linked list, immediately */
        /*   following `endpoint1'.                                        */
        linkringinsertatoms(pool, &position, 1, ghostatom,
                            proxipooltag2allocindex(pool, linkring));
      } else {
        /* Put the ghost vertex immediately before `endpoint2'. */
        linkringinsertatoms(pool, &pt2position, 1, ghostatom,
                            proxipooltag2allocindex(pool, linkring));
      }
      return 8;
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  linkringinsertvertex()   Insert a vertex into a link ring, immediately   */
/*                           following a specified vertex.                   */
/*                                                                           */
/*  The main purpose of this procedure is to provide a way to swap one edge  */
/*  for two.  For instance, if the link ring contains an edge 1-3, and you   */
/*  request that the vertex 2 be inserted after the vertex 1, then the edge  */
/*  1-3 is replaced by the edges 1-2 and 2-3.  (You can accomplish the same  */
/*  thing by calling linkringdeleteedge() and linkringinsertedge(), but it's */
/*  much slower.)                                                            */
/*                                                                           */
/*  If you're feeling sneaky, you can insert GHOSTVERTEX after vertex 1,     */
/*  thereby deleting the edge 1-3.  (But it's safer to do that with          */
/*  linkringdeleteedge().  Or you can insert a specified vertex after        */
/*  GHOSTVERTEX.  However, if there's more than one ghost vertex in the link */
/*  ring, you cannot control which ghost vertex the new vertex is inserted   */
/*  after.                                                                   */
/*                                                                           */
/*  WARNING:  For speed, this procedure does little error checking.  You can */
/*  inadvertently corrupt a link ring by inserting two copies of the same    */
/*  (non-ghost) vertex, or inserting a ghost vertex next to another ghost    */
/*  vertex.  You should never do the latter.  Inserting two copies of the    */
/*  same non-ghost vertex is useful for implementing the Bowyer-Watson       */
/*  algorithm, but if you do so, you cannot use linkringinsertedge() or      */
/*  linkringdeleteedge() to affect the duplicated vertex, and you must use   */
/*  linkringdelete2vertices() carefully to finish digging the cavity, so     */
/*  that the duplicated vertex will merge back into one copy in the end.     */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from, and that new */
/*    molecules may be allocated from.                                       */
/*  linkring:  Tag for the first molecule in the link ring.                  */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  searchvertex:  The tag of the vertex to search for.                      */
/*  newvertex:  The tag to insert after `searchvertex'.                      */
/*                                                                           */
/*  Returns 1 if `searchvertex' is in the link ring; 0 otherwise.  In the    */
/*    latter case, the link ring is not changed.                             */
/*                                                                           */
/*****************************************************************************/

int linkringinsertvertex(struct proxipool *pool,
                         tag linkring,
                         tag groundtag,
                         tag searchvertex,
                         tag newvertex)
{
  struct linkpossmall position;
  tag vertextag;
  int vertexatoms;
  int numatoms;
  char newvertexatoms[COMPRESSEDTAGLENGTH];
  char nowatom;

  if ((linkring >= STOP) ||
      (newvertex == searchvertex) || (newvertex == STOP)) {
    /* Invalid parameters. */
    return 0;
  }

  vertextag = 0;
  vertexatoms = 0;
  /* Start at the first molecule. */
  position.nextmoleculetag = linkring;

  /* Loop through the linked list of molecules. */
  do {
    /* Convert the molecule's tag to a pointer. */
    position.cule = (molecule) proxipooltag2object(pool, 
                                                   position.nextmoleculetag);
    position.moleculetag = position.nextmoleculetag;
    /* Read the "next molecule" tag. */
    linkringreadtag(position.moleculetag, position.cule,
                    position.lasttextindex, position.nextmoleculetag, nowatom,
                    "Internal error in linkringinsertvertex():\n");

    position.textindex = 0;
    /* Loop through the atoms, stopping at the "next molecule" tag. */
    while (position.textindex <= position.lasttextindex) {
      nowatom = position.cule[position.textindex];
      /* Append the atom to the vertex tag. */
      vertextag = (vertextag << 7) + (nowatom & (char) 127);
      vertexatoms++;
      position.textindex++;

      /* Is this the last atom in the compressed tag? */
      if (nowatom < (char) 0) {
        /* Yes; we have an uncompressed tag now.  What tag is it? */
        if ((nowatom == (char) STOP) && (vertexatoms == 1)) {
          /* STOP tag.  Exit the inner loop early; go on to next molecule. */
          break;
        } else if ((nowatom == (char) GHOSTVERTEX) && (vertexatoms == 1)) {
          /* Ghost vertex. */
          vertextag = GHOSTVERTEX;
        } else {
          /* Use the ground tag to supply the high-order bits. */
          vertextag += (groundtag >> (7 * vertexatoms)) << (7 * vertexatoms);
        }

        /* Is this the vertex we're searching for? */
        if (vertextag == searchvertex) {
          /* Insert the new vertex here and return. */
          numatoms = linkringtagcompress(groundtag, newvertex, newvertexatoms);
          linkringinsertatoms(pool, &position, numatoms, newvertexatoms,
                              proxipooltag2allocindex(pool, linkring));
          return 1;
        }

        /* Prepare to read another tag. */
        vertextag = 0;
        vertexatoms = 0;
      }
    }
  } while (position.nextmoleculetag != STOP);

  if (nowatom >= (char) 0) {
    /* Oops.  The end of the last vertex is missing from the last molecule. */
    printf("Internal error in linkringinsertvertex():\n");
    printf("  Link ring not properly terminated.\n");
    internalerror();
  }

  /* `searchvertex' is not in the link ring. */
  return 0;
}

/*****************************************************************************/
/*                                                                           */
/*  linkringdeletevertex()   Delete a vertex from a link ring.               */
/*                                                                           */
/*  The main purpose of this procedure is to provide a way to swap two edges */
/*  for one.  For instance, if the link ring contains the edges 1-2 and 2-3, */
/*  and you delete the vertex 2, then the two edges are replaced by the edge */
/*  1-3.  (You can accomplish the same thing by calling linkringdeleteedge() */
/*  and linkringinsertedge(), but it's much slower.)                         */
/*                                                                           */
/*  You can also use it to delete an edge from an end of a chain.  For       */
/*  example, if the edge 1-2 is the beginning of a chain (i.e. there is a    */
/*  ghost vertex before the vertex 1), then deleting the vertex 1 has the    */
/*  effect of deleting the edge 1-2.  If the edge 1-2 was the entire chain,  */
/*  then the vertex 2 survives as a lone vertex in the link ring, with ghost */
/*  vertices on both sides of it.  If you subsequently delete the vertex 2,  */
/*  this procedure will do the right thing and delete one of the ghost       */
/*  vertices as well.                                                        */
/*                                                                           */
/*  If you're feeling sneaky, you can delete GHOSTVERTEX, thereby creating   */
/*  an edge.  For example, deleting a ghost vertex between vertices 1 and 2  */
/*  creates the edge 1-2.  However, if there's more than one ghost vertex in */
/*  the link ring, you cannot control which ghost vertex is deleted.         */
/*                                                                           */
/*  WARNING:  If there is are multiple copies of `deletevertex' in the link  */
/*  ring (be it a ghost vertex or not), you cannot control which one gets    */
/*  deleted.                                                                 */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from.              */
/*  linkring:  Tag for the first molecule in the link ring.                  */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  deletevertex:  The tag to delete.                                        */
/*                                                                           */
/*  Returns one of the following values.                                     */
/*    -1:  If the link ring is empty on entry (so it is not changed).        */
/*     0:  If `deletevertex' is not present, and the link ring is unchanged  */
/*         (but not empty).                                                  */
/*     1:  If `deletevertex' was in the link ring on entry, and thus was     */
/*         deleted; but some other vertex survives.                          */
/*     3:  If `deletevertex' was the sole (non-ghost) vertex on entry, and   */
/*         thus was deleted, leaving the link ring empty.                    */
/*                                                                           */
/*    Hence, a positive return value implies that the vertex was deleted,    */
/*    and the 2's bit signifies whether the link ring is empty on return.    */
/*                                                                           */
/*****************************************************************************/

int linkringdeletevertex(struct proxipool *pool,
                         tag linkring,
                         tag groundtag,
                         tag deletevertex)
{
  struct linkpossmall position;
  struct linkpossmall deleteposition;
  struct linkpossmall ghostposition;
  molecule cule;
  tag nextmoleculetag;
  tag moleculetag;
  int atomindex;
  int lasttextindex;
  char nowatom;

  /* There is no "previous" vertex we've visited yet. */
  tag firstvertextag = STOP;
  tag prevvertextag = STOP;
  tag vertextag = 0;
  long vertexcount = 0;
  int vertexatoms = 0;
  int deleteatoms = 0;
  /* Set to 1 during the first iteration of the "do" loop. */
  int firstflag = 1;

  if (linkring >= STOP) {
    /* Not a link ring. */
    return 0;
  }

  /* Start at the first molecule. */
  nextmoleculetag = linkring;

  /* Loop through the linked list of molecules. */
  do {
    /* Convert the molecule's tag to a pointer. */
    cule = (molecule) proxipooltag2object(pool, nextmoleculetag);
    moleculetag = nextmoleculetag;
    /* Read the "next molecule" tag. */
    linkringreadtag(moleculetag, cule, lasttextindex, nextmoleculetag, nowatom,
                    "Internal error in linkringdeletevertex():\n");
    if (firstflag) {
      /* Position to delete atoms from the beginning of the linked list. */
      position.cule = cule;
      position.textindex = 0;
      position.lasttextindex = lasttextindex;
      position.nextmoleculetag = nextmoleculetag;
      firstflag = 0;
    }

    atomindex = 0;
    /* Loop through the atoms, stopping at the "next molecule" tag. */
    while (atomindex <= lasttextindex) {
      nowatom = cule[atomindex];
      /* Append the atom to the vertex tag. */
      vertextag = (vertextag << 7) + (nowatom & (char) 127);
      vertexatoms++;
      atomindex++;

      /* Is this the last atom in the compressed tag? */
      if (nowatom < (char) 0) {
        /* Yes; we have an uncompressed tag now.  What tag is it? */
        if ((nowatom == (char) STOP) && (vertexatoms == 1)) {
          /* STOP tag.  Exit the inner loop early; go on to next molecule. */
          break;
        } else if ((nowatom == (char) GHOSTVERTEX) && (vertexatoms == 1)) {
          vertextag = GHOSTVERTEX;
          /* Remember this position in case we need to delete the ghost. */
          ghostposition = position;
        } else {
          /* Use the ground tag to supply the high-order bits. */
          vertextag += (groundtag >> (7 * vertexatoms)) << (7 * vertexatoms);
        }

        vertexcount++;
        if (vertexcount == 1) {
          /* This is the first vertex.  Remember it. */
          firstvertextag = vertextag;
        }

        /* Is this the vertex we're searching for? */
        if (vertextag == deletevertex) {
          /* Yes.  If there are ghost vertices immediately before and after */
          /*   this vertex, we must delete one of them as well.  If this    */
          /*   vertex is at the beginning or end of the linked list, it     */
          /*   takes a bit of effort to check for this.                     */

          if ((prevvertextag != STOP) && (prevvertextag != GHOSTVERTEX)) {
            /* No ghost vertex before.  Just delete this vertex and return. */
            linkringdeleteatoms(pool, &position, vertexatoms);
            return 1;
          }

          /* Look ahead one atom to see if a ghost vertex is next. */
          if (atomindex <= lasttextindex) {
            nowatom = cule[atomindex];
          } else if (nextmoleculetag == STOP) {
            nowatom = (char) STOP;
          } else {
            /* The next atom is in the next molecule. */
            nowatom = ((molecule)
                       proxipooltag2object(pool, nextmoleculetag))[0];
          }

          if ((nowatom != (char) GHOSTVERTEX) &&
              ((nowatom != (char) STOP) ||
               (firstvertextag != GHOSTVERTEX))) {
            /* No ghost vertex after.  Just delete this vertex and return. */
            if ((vertexcount == 1) && (nowatom == (char) STOP)) {
              /* Empty the link ring. */
              linkringrestart(pool, linkring);
              return 3;
            } else {
              linkringdeleteatoms(pool, &position, vertexatoms);
              return 1;
            }
          }

          if (prevvertextag == GHOSTVERTEX) {
            /* Ghost vertex before and after.  Delete this vertex and the */
            /*   ghost vertex preceding it.  (Note that this also handles */
            /*   the case where there are only two vertices in the link   */
            /*   ring, so the same ghost vertex is before and after.)     */
            if ((vertexcount == 2) && (nowatom == (char) STOP)) {
              /* Empty the link ring. */
              linkringrestart(pool, linkring);
              return 3;
            } else {
              linkringdeleteatoms(pool, &ghostposition, vertexatoms + 1);
              return 1;
            }
          }

          /* If execution reaches this point, there is a ghost vertex after */
          /*   the vertex we want to delete; but `deletevertex' is at the   */
          /*   beginning of the linked list, so we won't know if there's a  */
          /*   ghost vertex before until we reach the end of the list.      */
          /*   Save this vertex's position for later deletion.              */
          deleteposition = position;
          deleteatoms = vertexatoms;
        }

        /* Remember this tag during the next iteration. */
        prevvertextag = vertextag;
        /* Prepare to read another tag. */
        vertextag = 0;
        vertexatoms = 0;

        /* Store the position of the beginning of the next compressed tag,   */
        /*   in case we realize we need it once we reach the end of the tag. */
        position.cule = cule;
        position.textindex = atomindex;
        position.lasttextindex = lasttextindex;
        position.nextmoleculetag = nextmoleculetag;
      }
    }
  } while (nextmoleculetag != STOP);

  if (nowatom >= (char) 0) {
    /* Oops.  The end of the last vertex is missing from the last molecule. */
    printf("Internal error in linkringdeletevertex():\n");
    printf("  Vertex at end of link ring not properly terminated.\n");
    internalerror();
  }

  /* If execution reaches here, either `deletevertex' is absent from the */
  /*   link ring, or the linked list begins with `deletevertex' followed */
  /*   by a ghost vertex.                                                */

  if (firstvertextag == deletevertex) {
    /* The linked list begins with `deletevertex' and a ghost vertex */
    /*   immediately following it.                                   */
    if (vertexcount <= 2) {
      /* Empty the link ring. */
      linkringrestart(pool, linkring);
      return 3;
    } else if (prevvertextag == GHOSTVERTEX) {
      /* The linked list ends with a ghost vertex, which immediately      */
      /*   precedes `deletevertex' in the link ring.  Delete the ghost    */
      /*   vertex at the end.  (It's better to leave a ghost vertex at    */
      /*   the beginning, to reduce the frequency of having to go through */
      /*   the whole list just to see if there's a ghost at the end.)     */
      linkringdeleteatoms(pool, &ghostposition, 1);
      /* The deletion above may have changed the "next molecule" tag stored */
      /*   in the molecule at `deleteposition' to STOP.                     */
      if (deleteposition.cule[MOLECULESIZE - 1] == (char) STOP) {
        deleteposition.nextmoleculetag = STOP;
        deleteposition.lasttextindex = MOLECULESIZE - 2;
      }
    }
    /* Delete the target vertex. */
    linkringdeleteatoms(pool, &deleteposition, deleteatoms);
    return 1;
  }

  /* `deletevertex' is not in the link ring. */
  if (vertexcount == 0) {
    return -1;
  } else {
    return 0;
  }
}

/*****************************************************************************/
/*                                                                           */
/*  linkringdelete2vertices()   Delete a vertex and the vertex that follows  */
/*                              it from a link ring.                         */
/*                                                                           */
/*  This procedure differs from linkringdeletevertex() in that it does not   */
/*  check whether the deletion puts two ghost vertices next to each other;   */
/*  nor does it check whether the resulting link ring contains just one      */
/*  vertex (ghost or not).  It should not be used in circumstances where it  */
/*  will cause one of these problems.                                        */
/*                                                                           */
/*  The procedure's purpose is to help implement the Bowyer-Watson algorithm */
/*  for incremental insertion of a vertex into a Delaunay triangulation.     */
/*  It is used in the circumstance where the link ring contains two (or      */
/*  more) copies of the new vertex being inserted, with `deletevertex'       */
/*  sandwiched between them, which the Bowyer-Watson algorithm wants to      */
/*  delete.  Deleting just `deletevertex' would put two copies of the new    */
/*  vertex next to each other, but they should be merged into a single copy. */
/*  Therefore, this procedure deletes `deletevertex' and the vertex          */
/*  following it (which should be a copy of the new vertex) at once, leaving */
/*  behind one copy of the new vertex.  (That's why there are no checks for  */
/*  adjacent ghost vertices, nor for a one-vertex link ring.)  This          */
/*  procedure also works correctly in the case where there are only two      */
/*  vertices in the link ring, so the copies of the new vertex (before and   */
/*  after `deletevertex') are really the same copy.                          */
/*                                                                           */
/*  The procedure could be used for other purposes as well, so long as there */
/*  is no possibility of putting two ghost vertices together, or leaving     */
/*  behind just one ghost vertex and no other vertex.                        */
/*                                                                           */
/*  pool:  The proxipool that the link ring was allocated from.              */
/*  linkring:  Tag for the first molecule in the link ring.                  */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  deletevertex:  The tag to delete, along with its successor.              */
/*                                                                           */
/*  Returns one of the following values.                                     */
/*    -1:  If the link ring is empty on entry (so it is not changed).        */
/*     0:  If `deletevertex' is not present, and the link ring is unchanged  */
/*         (but not empty).                                                  */
/*     1:  If `deletevertex' was in the link ring on entry, and thus was     */
/*         deleted (with its successor); but some other vertex survives.     */
/*     3:  If `deletevertex' was deleted, and the link ring is now empty.    */
/*                                                                           */
/*    Hence, a positive return value implies that the vertex was deleted,    */
/*    and the 2's bit signifies whether the link ring is empty on return.    */
/*                                                                           */
/*****************************************************************************/

int linkringdelete2vertices(struct proxipool *pool,
                            tag linkring,
                            tag groundtag,
                            tag deletevertex)
{
  struct linkpossmall position;
  struct linkpossmall deleteposition;
  molecule cule;
  tag nextmoleculetag;
  tag moleculetag;
  int atomindex;
  int lasttextindex;
  char nowatom;

  /* There is no "previous" vertex we've visited yet. */
  tag prevvertextag = STOP;
  tag vertextag = 0;
  long vertexcount = 0;
  int vertexatoms = 0;
  int deleteatoms = 0;
  int firstatoms = 0;
  /* Set to 1 during the first iteration of the "do" loop. */
  int firstflag = 1;

  if (linkring >= STOP) {
    /* Not a link ring. */
    return 0;
  }

  /* Start at the first molecule. */
  nextmoleculetag = linkring;

  /* Loop through the linked list of molecules. */
  do {
    /* Convert the molecule's tag to a pointer. */
    cule = (molecule) proxipooltag2object(pool, nextmoleculetag);
    moleculetag = nextmoleculetag;
    /* Read the "next molecule" tag. */
    linkringreadtag(moleculetag, cule, lasttextindex, nextmoleculetag, nowatom,
                    "Internal error in linkringdelete2vertices():\n");
    if (firstflag) {
      /* Position to delete atoms from the beginning of the linked list. */
      position.cule = cule;
      position.textindex = 0;
      position.lasttextindex = lasttextindex;
      position.nextmoleculetag = nextmoleculetag;
      firstflag = 0;
    }

    atomindex = 0;
    /* Loop through the atoms, stopping at the "next molecule" tag. */
    while (atomindex <= lasttextindex) {
      nowatom = cule[atomindex];
      /* Append the atom to the vertex tag. */
      vertextag = (vertextag << 7) + (nowatom & (char) 127);
      vertexatoms++;
      atomindex++;

      /* Is this the last atom in the compressed tag? */
      if (nowatom < (char) 0) {
        /* Yes; we have an uncompressed tag now.  What tag is it? */
        if ((nowatom == (char) STOP) && (vertexatoms == 1)) {
          /* STOP tag.  Exit the inner loop early; go on to next molecule. */
          break;
        } else if ((nowatom == (char) GHOSTVERTEX) && (vertexatoms == 1)) {
          vertextag = GHOSTVERTEX;
        } else {
          /* Use the ground tag to supply the high-order bits. */
          vertextag += (groundtag >> (7 * vertexatoms)) << (7 * vertexatoms);
        }

        vertexcount++;
        if (vertexcount == 1) {
          /* This is the first vertex.  Remember its length. */
          firstatoms = vertexatoms;
        }

        /* Is the previous vertex the one we want to delete? */
        if (prevvertextag == deletevertex) {
          /* Yes; delete `deletevertex' and the following vertex. */
          linkringdeleteatoms(pool, &deleteposition,
                              deleteatoms + vertexatoms);
          /* Is the link ring empty now? */
          if ((vertexcount == 2) &&
              (((molecule) proxipooltag2object(pool, linkring))[0] ==
               (char) STOP)) {
            /* Yes. */
            return 3;
          } else {
            return 1;
          }
        } else if (vertextag == deletevertex) {
          /* This is the vertex we want to delete.  Remember its position. */
          deleteposition = position;
          deleteatoms = vertexatoms;
        }

        /* Remember this tag during the next iteration. */
        prevvertextag = vertextag;
        /* Prepare to read another tag. */
        vertextag = 0;
        vertexatoms = 0;

        /* Store the position of the beginning of the next compressed tag,   */
        /*   in case we realize we need it once we reach the end of the tag. */
        position.cule = cule;
        position.textindex = atomindex;
        position.lasttextindex = lasttextindex;
        position.nextmoleculetag = nextmoleculetag;
      }
    }
  } while (nextmoleculetag != STOP);

  if (nowatom >= (char) 0) {
    /* Oops.  The end of the last vertex is missing from the last molecule. */
    printf("Internal error in linkringdelete2vertices():\n");
    printf("  Vertex at end of link ring not properly terminated.\n");
    internalerror();
  }

  /* If execution reaches here, either `deletevertex' is absent from the */
  /*   link ring, or the linked list ends with `deletevertex'.           */

  if (prevvertextag == deletevertex) {
    if (vertexcount <= 2) {
      /* Empty the link ring. */
      linkringrestart(pool, linkring);
      return 3;
    } else {
      /* Delete `deletevertex' from the end first. */
      linkringdeleteatoms(pool, &deleteposition, deleteatoms);
      /* Delete one of the vertex copies from the beginning.  Note that the */
      /*   deletion above may have changed the first molecule in the list,  */
      /*   so we must re-read it.                                           */
      position.cule = (molecule) proxipooltag2object(pool, linkring);
      position.textindex = 0;
      linkringreadtag(linkring, position.cule, position.lasttextindex,
                      position.nextmoleculetag, nowatom,
                      "Internal error in linkringdelete2vertices():\n");
      linkringdeleteatoms(pool, &position, firstatoms);
      return 1;
    }
  }

  /* `deletevertex' is not in the link ring. */
  if (vertexcount == 0) {
    return -1;
  } else {
    return 0;
  }
}

/**                                                                         **/
/**                                                                         **/
/********* Link ring routines end here                               *********/


/********* 2D link/triangulation representation routines begin here  *********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  Compressed 2D links                                                      */
/*                                                                           */
/*  The link of a vertex in a 3D triangulation is a topologically two-       */
/*  dimensional triangulation, embedded in 3D space.  If the vertex is in    */
/*  the interior of the triangulation, then its link is a triangulation of a */
/*  topological sphere.  (This data structure can store the link of any      */
/*  vertex in a 3D triangulation, though.)                                   */
/*                                                                           */
/*  The triangles in a 2D link should be thought of as sharing a fixed       */
/*  "orientation".  I choose the orientation that has the vertices of each   */
/*  triangle in counterclockwise order, as viewed by the vertex whose link   */
/*  it is.  Here I'm assuming that there are no geometrically "inverted"     */
/*  tetrahedra, but this code is deliberately oblivious to geometry--it      */
/*  never looks at a coordinate.  You could use all-clockwise if you prefer. */
/*  However, the topological orientations of the triangles should all be     */
/*  mutually consistent.  You could not, for example, represent an           */
/*  unoriented manifold (e.g. a Mobius strip or Klein bottle).               */
/*                                                                           */
/*  2D links are stored in a compressed format adapted from Blandford,       */
/*  Blelloch, Cardoze, and Kadow.  See the header for a full citation.       */
/*                                                                           */
/*  Each link ring is stored in a linked list of list nodes of type          */
/*  `molecule'.  Molecules are described in the comments for "Compressed     */
/*  link rings."  2D links use essentially the same representation, and have */
/*  mostly the same invariants, as link rings.  The molecules for 2D links   */
/*  and link rings are allocated from the same proxipool.                    */
/*                                                                           */
/*  Here are the invariants of 2D links that differ from link rings:         */
/*                                                                           */
/*  - The compressed tags in the linked list alternate between vertex tags   */
/*    and link ring tags.  Each vertex in the list is followed by the tag    */
/*    for its link ring.                                                     */
/*                                                                           */
/*  - Vertices in a 2D link may appear in any order.  Their order is not     */
/*    relevant.                                                              */
/*                                                                           */
/*  - A 2D link can contain a GHOSTVERTEX, but only one.  In a 2D link, the  */
/*    link ring of a ghost vertex represents ghost triangles and ghost       */
/*    tetrahedra.                                                            */
/*                                                                           */
/*  - A 2D link cannot contain an empty link ring.  When a link ring empties */
/*    out, it must be removed from any 2D link that contains it.             */
/*                                                                           */
/*  - Whereas each vertex tag is compressed against a "ground tag" (just     */
/*    like in link rings), each link ring tag is compressed against the tag  */
/*    for the 2D link.                                                       */
/*                                                                           */
/*  Public interface:                                                        */
/*  GHOSTVERTEX   Tag representing a ghost vertex; borrowed from linkring.   */
/*  STOP   Tag representing an unsuccessful query; borrowed from linkring.   */
/*  link2dcache   Type for a cache used to speed up link2dfindring().        */
/*  struct link2dposition   Represents a position in a 2D link.              */
/*  tag link2dnew(pool, allocindex)   Allocate a new, empty 2D link.         */
/*  void link2ddelete(pool, link)   Free a 2D link to the pool.              */
/*  void link2disempty(pool, link)   Determine if a 2D link is empty.        */
/*  void link2dcacheinit(cache)   Initialize/reset a 2D link cache to empty. */
/*  tag link2dfindring(pool, cache, link, groundtag, searchvertex)   Return  */
/*    the link ring associated with a vertex in a 2D link.                   */
/*  tag link2dfindinsert(pool, cache, linkhead, linktail, groundtag,         */
/*    searchvertex)   Return or create a vertex/link ring in a 2D link.      */
/*  void link2dinsertvertex(pool, cache, linkhead, linktail, groundtag,      */
/*    newvertex, linkring)   Insert a vertex/link ring in a 2D link.         */
/*  tag link2ddeletevertex(pool, cache, linkhead, linktail, groundtag,       */
/*    deletevertex)   Delete a vertex from a 2D link; return link ring.      */
/*  void link2diteratorinit(pool, link, groundtag, pos)   Initialize an      */
/*    iterator that traverses all the vertices in a link ring one by one.    */
/*  void link2diterate(pos, vertexandlink[2])   Read two tags (for a vertex  */
/*    and its link ring) and advance the iterator.                           */
/*  void link2dprint(pool, link, grountag)   Print the contents of a link.   */
/*                                                                           */
/*  For internal use only:                                                   */
/*  tag link2dfindringnocache(pool, link, groundtag, searchvertex)   Return  */
/*    the link ring associated with a vertex in a 2D link.                   */
/*  void link2dinsertvertexnocache(pool, linkhead, linktail, groundtag,      */
/*    newvertex, linkring)   Insert a vertex/link ring in a 2D link.         */
/*  tag link2ddeletevertexnocache(pool, linkhead, linktail, groundtag,       */
/*    deletevertex)   Delete a vertex from a 2D link; return link ring.      */
/*                                                                           */
/*****************************************************************************/

/*****************************************************************************/
/*                                                                           */
/*  The 2D link cache                                                        */
/*                                                                           */
/*  A user of the link2d procedures may optionally use a cache of type       */
/*  "link2dcache" to speed up the link2dfindring() procedure.  In my         */
/*  Delaunay triangulation implementation, this improves link2dfindring()    */
/*  from taking about 30% of the running time to taking about 3.5% of the    */
/*  running time.                                                            */
/*                                                                           */
/*  A cache should be initialized with link2dcacheinit() before use.  Once   */
/*  used, the cache must be passed to all subsequent calls to                */
/*  link2dinsertvertex(), link2dfindinsert(), and link2ddeletevertex() on    */
/*  the same proxipool.  Otherwise, the cache will be out of date, and       */
/*  link2dfindring() may subsequently return out-of-date information.  The   */
/*  cache is passed to link2dfindring() to improve its speed.                */
/*                                                                           */
/*  A cache cannot be used for more than one link proxipool simultaneously.  */
/*  The cache simply maps a 2D link tag and a vertex tag to a link ring tag, */
/*  with no knowledge of what pools the tags are drawn from.                 */
/*                                                                           */
/*  Any procedure that takes a cache as a parameter will accept a NULL       */
/*  pointer (if you don't want to bother with cacheing).                     */
/*                                                                           */
/*****************************************************************************/

/*  LINK2DCACHESIZE is the total number of entries in the cache that speeds  */
/*  up lookup of vertices in 2D links.  Because the cache is two-way         */
/*  associative, the number of buckets is half this number.  LINK2DCACHESIZE */
/*  _must_ be a power of two.                                                */

#define LINK2DCACHESIZE 16384

/*  LINK2DPRIME is a prime number used in a (not very good) hash function.   */

#define LINK2DPRIME 16908799u


/*  A link2dcache is an array that caches the link rings for 2D link/vertex  */
/*  pairs that have been recently looked up or updated.  A link cache        */
/*  greatly speeds up the link2dfindring() procedure.                        */

typedef struct {
  tag mylink2d;
  tag myvertex;
  tag mylinkring;
} link2dcache[LINK2DCACHESIZE];

/*  A link2dposition represents an atom in a 2D link.  It is the data        */
/*  structure used as an iterator that walks through a 2D link.              */

struct link2dposition {
  struct linkposition innerpos;                  /* Position in the 2D link. */
  tag linktag;     /* Tag for the link's first molecule, used to decompress. */
};


/*****************************************************************************/
/*                                                                           */
/*  link2dnew()   Allocate a new, empty 2D link triangulation.               */
/*                                                                           */
/*  The parameters include an allocation index, used to determine where the  */
/*  new link will be stored in memory.  Links with the same allocation index */
/*  go into common areas in memory.  The idea is to create spatial           */
/*  coherence:  links that are geometrically close to each other are near    */
/*  each other in memory, too.                                               */
/*                                                                           */
/*  pool:  The proxipool to allocate the link from.                          */
/*  allocindex:  An allocation index associated with the link.               */
/*                                                                           */
/*  Returns the tag of the first (and only) molecule of the new link.        */
/*                                                                           */
/*****************************************************************************/

tag link2dnew(struct proxipool *pool,
              proxipoolulong allocindex)
{
  molecule cule;
  tag newlink;

  /* Allocate a molecule to hold the (empty) link triangulation. */
  newlink = proxipoolnew(pool, allocindex, (void **) &cule);
  /* There are no vertices in this link. */
  cule[0] = (char) STOP;
  /* There is no next molecule. */
  cule[MOLECULESIZE - 1] = (char) STOP;

  return newlink;
}

/*****************************************************************************/
/*                                                                           */
/*  link2ddelete()   Free all the molecules in a 2D link to the pool.        */
/*                                                                           */
/*  Does not free the link rings referenced by the link.                     */
/*                                                                           */
/*  WARNING:  If a "link2dcache" is in use, this procedure does not clear    */
/*  entries in this 2D link from the cache.  If `link' is not empty, then    */
/*  then you should clear the cache with link2dcacheinit().                  */
/*                                                                           */
/*  pool:  The proxipool that the molecules were allocated from.             */
/*  link:  Tag for the first molecule in the link.                           */
/*                                                                           */
/*****************************************************************************/

void link2ddelete(struct proxipool *pool,
                  tag link)
{
  molecule cule;
  tag nextmoleculetag;
  tag moleculetag;
  int atomindex;
  char nowatom;

  if (link >= STOP) {
    return;
  }

  nextmoleculetag = link;

  /* Loop through the molecules and free them. */
  while (nextmoleculetag != STOP) {
    /* Convert the tag to a molecule. */
    cule = (molecule) proxipooltag2object(pool, nextmoleculetag);
#ifdef SELF_CHECK
    if (cule == (molecule) NULL) {
      printf("Internal error in link2ddelete():\n");
      printf("  Molecule tag indexes a NULL pointer.\n");
      internalerror();
    }
#endif /* SELF_CHECK */
    moleculetag = nextmoleculetag;
    /* Read the "next molecule tag". */
    linkringreadtag(moleculetag, cule, atomindex, nextmoleculetag, nowatom,
                    "Internal error in link2ddelete():\n");
    /* Free the molecule. */
    proxipoolfree(pool, moleculetag);
  }
}

/*****************************************************************************/
/*                                                                           */
/*  link2disempty()   Determine if a 2D link is empty (or invalid).          */
/*                                                                           */
/*  pool:  The proxipool that the link was allocated from.                   */
/*  link:  Tag for the first molecule in the link.                           */
/*                                                                           */
/*  Returns 1 if the 2D link is empty (or the tag is invalid); 0 otherwise.  */
/*                                                                           */
/*****************************************************************************/

int link2disempty(struct proxipool *pool,
                  tag link)
{
  molecule cule;

  if (link >= STOP) {
    /* Not a valid link tag. */
    return 1;
  }

  /* Convert the tag to a molecule. */
  cule = (molecule) proxipooltag2object(pool, link);
  if ((cule == (molecule) NULL) || (cule[0] == (char) STOP)) {
    /* Missing or empty link. */
    return 1;
  } else {
    /* Not empty. */
    return 0;
  }
}

/*****************************************************************************/
/*                                                                           */
/*  link2diteratorinit()   Initialize an iterator that traverses all the     */
/*                         vertices in a link one by one.                    */
/*                                                                           */
/*  The iterator is a variable `pos', whose internals should not be          */
/*  examined or modified by the client.  The iterator's job is to keep       */
/*  track of where it is in the link.  This procedure sets the iterator to   */
/*  reference the first vertex in the link.                                  */
/*                                                                           */
/*  When a link is modified, any iterators on that link may be corrupted and */
/*  should not be used without being initialized (by this procedure) again.  */
/*                                                                           */
/*  pool:  The proxipool that the link was allocated from.                   */
/*  link:  Tag for the first molecule in the link to traverse.               */
/*  groundtag:  The ground tag relative to which the vertices in the link    */
/*    will be decompressed.                                                  */
/*  pos:  The iterator.  Its contents do not need to be initialized prior to */
/*    calling this procedure.                                                */
/*                                                                           */
/*****************************************************************************/

void link2diteratorinit(struct proxipool *pool,
                        tag link,
                        tag groundtag,
                        struct link2dposition *pos)
{
  char nowatom;

  pos->linktag = link;
  pos->innerpos.groundtag = groundtag;
  pos->innerpos.pool = pool;
  if (link >= STOP) {
    /* Not a link. */
    pos->innerpos.cule = (molecule) NULL;
    pos->innerpos.moleculetag = STOP;
    pos->innerpos.nextmoleculetag = STOP;
    pos->innerpos.textindex = MOLECULESIZE;
    pos->innerpos.lasttextindex = -1;
  } else {
    /* Find the molecule identified by the tag `link'. */
    pos->innerpos.cule = (molecule) proxipooltag2object(pool, link);
#ifdef SELF_CHECK
    if (pos->innerpos.cule == (molecule) NULL) {
      printf("Internal error in link2diteratorinit():\n");
      printf("  Molecule tag indexes a NULL pointer.\n");
      internalerror();
    }
#endif /* SELF_CHECK */
    pos->innerpos.moleculetag = link;
    /* Read the molecule's "next molecule tag". */
    linkringreadtag(link, pos->innerpos.cule, pos->innerpos.lasttextindex,
                    pos->innerpos.nextmoleculetag, nowatom,
                    "Internal error in link2diteratorinit():\n");
    /* Start the iterations from the beginning of the molecule. */
    pos->innerpos.textindex = 0;
  }
}

/*****************************************************************************/
/*                                                                           */
/*  link2diterate()   Return the two tags (for a vertex and its link ring)   */
/*                    that a 2D link iterator references, and advance the    */
/*                    iterator so it will return the next vertex next time.  */
/*                                                                           */
/*  The iterator is a variable `pos', whose internals should not be          */
/*  examined or modified by the client.                                      */
/*                                                                           */
/*  After a link is modified, any iterators on that link created before the  */
/*  modification may be corrupted and should not be passed to this procedure */
/*  again until they are re-initialized.                                     */
/*                                                                           */
/*  pos:  The iterator.                                                      */
/*  vertexandlink:  An array used to return the tags for a vertex (in        */
/*    vertexandlink[0]) and the link ring associated with it (in             */
/*    vertexandlink[1]).  If the iterator has reached the end of the list,   */
/*    both values will be STOP on return.  Does not need to be initialized   */
/*    before the call.                                                       */
/*                                                                           */
/*****************************************************************************/

void link2diterate(struct link2dposition *pos,
                   tag vertexandlink[2])
{
  tag texttag;
  int textatoms;
  int vertextagflag;
  char nowatom;

  texttag = 0;
  textatoms = 0;
  /* Set to 1 while reading a vertex tag; 0 when reading a link ring tag. */
  vertextagflag = 1;

  /* Loop through atoms to build up two tags. */
  while (1) {
    /* Have we read the last text atom in this molecule? */
    if ((pos->innerpos.textindex > pos->innerpos.lasttextindex) ||
        ((pos->innerpos.cule[pos->innerpos.textindex] == (char) STOP) &&
         (textatoms == 0))) {
      /* Yes, we have.  Are there any more molecules after this one? */
      if (pos->innerpos.nextmoleculetag == STOP) {
        /* No, there aren't.  The iterator is finished. */
#ifdef SELF_CHECK
        if (textatoms > 0) {
          /* The end of the last tag is missing from the last molecule. */
          printf("Internal error in link2diterate():\n");
          printf("  Tag at end of 2D link not properly terminated.\n");
          internalerror();
        }
        if (!vertextagflag) {
          /* There is a vertex tag without a link ring tag following it. */
          printf("Internal error in link2diterate():\n");
          printf("  Vertex tag not followed by link ring tag.\n");
          internalerror();
        }
#endif /* SELF_CHECK */

        vertexandlink[0] = STOP;
        vertexandlink[1] = STOP;
        return;
      }

      /* Find the next molecule in the linked list. */
      pos->innerpos.cule =
        (molecule) proxipooltag2object(pos->innerpos.pool,
                                       pos->innerpos.nextmoleculetag);
#ifdef SELF_CHECK
      if (pos->innerpos.cule == (molecule) NULL) {
        printf("Internal error in link2diterate():\n");
        printf("  Molecule tag indexes a NULL pointer.\n");
        internalerror();
      }
#endif /* SELF_CHECK */
      pos->innerpos.moleculetag = pos->innerpos.nextmoleculetag;
      /* Find the next molecule's "next molecule tag". */
      linkringreadtag(pos->innerpos.moleculetag, pos->innerpos.cule,
                      pos->innerpos.lasttextindex,
                      pos->innerpos.nextmoleculetag, nowatom,
                      "Internal error in link2diterate():\n");
      /* Start from the beginning of this molecule. */
      pos->innerpos.textindex = 0;
    }

    /* Read the next atom. */
    nowatom = pos->innerpos.cule[pos->innerpos.textindex];
    /* Append it to the tag. */
    texttag = (texttag << 7) + (nowatom & (char) 127);
    textatoms++;
    pos->innerpos.textindex++;

    /* If this is the end of a tag, store it for the caller. */
    if (nowatom < (char) 0) {
      if (vertextagflag) {
        if ((nowatom == (char) GHOSTVERTEX) && (textatoms == 1)) {
          vertexandlink[0] = GHOSTVERTEX;
        } else {
          /* Get the high-order bits from the ground vertex's tag. */
          vertexandlink[0] = texttag +
            ((pos->innerpos.groundtag >> (7 * textatoms)) << (7 * textatoms));
        }
        /* Prepare to read another tag. */
        texttag = 0;
        textatoms = 0;
        vertextagflag = 0;
      } else {
        /* Get the high-order bits from the first molecule's tag. */
        vertexandlink[1] = texttag +
          ((pos->linktag >> (7 * textatoms)) << (7 * textatoms));
        return;
      }
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  link2dprint()   Print the contents of a 2D link.                         */
/*                                                                           */
/*  pool:  The proxipool that the link was allocated from.                   */
/*  link:  Tag for the first molecule in the link.                           */
/*  groundtag:  The ground tag relative to which the vertices in the link    */
/*    will be decompressed.                                                  */
/*                                                                           */
/*****************************************************************************/

void link2dprint(struct proxipool *pool,
                 tag link,
                 tag groundtag)
{
  struct link2dposition pos;
  tag vertexandlink[2];

  printf("2D link %lu:\n", (unsigned long) link);
  link2diteratorinit(pool, link, groundtag, &pos);
  link2diterate(&pos, vertexandlink);
  if (vertexandlink[0] == STOP) {
    printf("  EMPTY\n");
  } else do {
    if (vertexandlink[0] == GHOSTVERTEX) {
      printf("  Vertex tag GHOST, ");
    } else {
      printf("  Vertex tag %lu, ", (unsigned long) vertexandlink[0]);
    }
    linkringprint(pool, vertexandlink[1], groundtag);
    link2diterate(&pos, vertexandlink);
  } while (vertexandlink[0] != STOP);
}

/*****************************************************************************/
/*                                                                           */
/*  link2dcacheinit()   Reset a 2D link cache to empty.                      */
/*                                                                           */
/*  A "link2dcache" should always be initialized before use.  It should also */
/*  be cleared by this procedure if you use link2ddelete() to free a 2D link */
/*  that is not empty.                                                       */
/*                                                                           */
/*  cache:  The cache to initialize.                                         */
/*                                                                           */
/*****************************************************************************/

void link2dcacheinit(link2dcache cache) {
  int i;

  for (i = 0; i < LINK2DCACHESIZE; i++) {
    cache[i].mylink2d = STOP;
  }
}

/*****************************************************************************/
/*                                                                           */
/*  link2dfindringnocache()   Return the link ring associated with a vertex  */
/*                            in a 2D link.                                  */
/*                                                                           */
/*  pool:  The proxipool that the link was allocated from.                   */
/*  link:  Tag for the first molecule in the link.                           */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  searchvertex:  The tag of the vertex to search for.                      */
/*  linktail:  If (and only if) `searchvertex' is missing from the link AND  */
/*    `linktail' is not NULL, then on return, `*linktail' contains the tag   */
/*    for the last molecule in the 2D link.  Output only; the value of       */
/*    `*linktail' on entry is irrelevant.  Set `linktail' to NULL if you     */
/*    don't want this information.                                           */
/*                                                                           */
/*  Returns the tag of the link ring associated with `searchvertex' if       */
/*    `searchvertex' is in the link; STOP otherwise.                         */
/*                                                                           */
/*****************************************************************************/

tag link2dfindringnocache(struct proxipool *pool,
                          tag link,
                          tag groundtag,
                          tag searchvertex,
                          tag *linktail)
{
  molecule cule;
  tag nextmoleculetag;
  tag moleculetag;
  tag texttag;
  int textatoms;
  int atomindex;
  int lasttextindex;
  int vertextagflag;
  int matchflag;
  char nowatom;

  if (link >= STOP) {
    /* Not a link. */
    return STOP;
  }

  texttag = 0;
  textatoms = 0;
  /* Start at the first molecule. */
  nextmoleculetag = link;
  /* Set to 1 while reading a vertex tag; 0 when reading a link ring tag. */
  vertextagflag = 1;
  matchflag = 0;

  /* Loop through the linked list of molecules. */
  do {
    /* Convert the molecule's tag to a pointer. */
    cule = (molecule) proxipooltag2object(pool, nextmoleculetag);
#ifdef SELF_CHECK
    if (cule == (molecule) NULL) {
      printf("Internal error in link2dfindringnocache():\n");
      printf("  Molecule tag indexes a NULL pointer.\n");
      internalerror();
    }
#endif /* SELF_CHECK */
    moleculetag = nextmoleculetag;
    /* Read the "next molecule tag". */
    linkringreadtag(moleculetag, cule, lasttextindex, nextmoleculetag, nowatom,
                    "Internal error in link2dfindringnocache():\n");

    atomindex = 0;
    /* Loop through the atoms, stopping at the "next molecule tag". */
    while (atomindex <= lasttextindex) {
      nowatom = cule[atomindex];
      /* Append the atom to the text tag. */
      texttag = (texttag << 7) + (nowatom & (char) 127);
      textatoms++;
      atomindex++;

      /* Is this the last atom in the compressed tag? */
      if (nowatom < (char) 0) {
        /* Yes; we have an uncompressed tag now.  What tag is it? */
        if ((nowatom == (char) STOP) && (textatoms == 1)) {
          /* STOP tag.  Exit the inner loop early; go on to next molecule. */
          break;
        } else if (vertextagflag) {
          /* Is this the vertex we're searching for? */
          if ((nowatom == (char) GHOSTVERTEX) && (textatoms == 1)) {
            /* Ghost vertex. */
            matchflag = searchvertex == GHOSTVERTEX;
          } else {
            /* Use the ground tag to supply the high-order bits of the */
            /*   vertex tag.                                           */
            matchflag =
              searchvertex ==
              texttag + ((groundtag >> (7 * textatoms)) << (7 * textatoms));
          }
        } else if (matchflag) {
          /* Use the link tag to supply the high-order bits of the */
          /*   link ring.  Return the latter.                      */
          return texttag + ((link >> (7 * textatoms)) << (7 * textatoms));
        }

        /* Prepare to read another tag. */
        texttag = 0;
        textatoms = 0;
        /* Alternate between reading vertex tags and link ring tags. */
        vertextagflag = !vertextagflag;
      }
    }
  } while (nextmoleculetag != STOP);

#ifdef SELF_CHECK
  if (nowatom >= (char) 0) {
    /* Oops.  The end of the last tag is missing from the last molecule. */
    printf("Internal error in link2dfindringnocache():\n");
    printf("  Tag at end of 2D link not properly terminated.\n");
    internalerror();
  }
  if (!vertextagflag) {
    /* There is a vertex tag without a link ring tag following it. */
    printf("Internal error in link2dfindringnocache():\n");
    printf("  Vertex tag not followed by link ring tag.\n");
    internalerror();
  }
#endif /* SELF_CHECK */

  /* `searchvertex' is not in the link. */
  if (linktail != (tag *) NULL) {
    *linktail = moleculetag;
  }
  return STOP;
}

/*****************************************************************************/
/*                                                                           */
/*  link2dfindring()   Return the link ring associated with a vertex in a 2D */
/*                     link.                                                 */
/*                                                                           */
/*  Resorts to calling link2dfindringnocache() if the answer is not in the   */
/*  cache.                                                                   */
/*                                                                           */
/*  pool:  The proxipool that the link was allocated from.                   */
/*  cache:  An (optional) cache that may speed up the lookup.                */
/*  link:  Tag for the first molecule in the link.                           */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  searchvertex:  The tag of the vertex to search for.                      */
/*                                                                           */
/*  Returns the tag of the link ring associated with `searchvertex' if       */
/*    `searchvertex' is in the link; STOP otherwise.                         */
/*                                                                           */
/*****************************************************************************/

tag link2dfindring(struct proxipool *pool,
                   link2dcache cache,
                   tag link,
                   tag groundtag,
                   tag searchvertex)
{
  int hash;
  tag linkring;

  if (link >= STOP) {
    /* Not a link. */
    return STOP;
  } else if (cache == NULL) {
    return link2dfindringnocache(pool, link, groundtag, searchvertex,
                                 (tag *) NULL);
  }

  /* Hash the tags `link' and `searchvertex' to an even location in the */
  /*   cache.                                                           */
  hash = (LINK2DPRIME * link * link + 2u * searchvertex) &
         (LINK2DCACHESIZE - 2);
  /* Is cache entry at the even location a hit? */
  if ((cache[hash].mylink2d == link) &&
      (cache[hash].myvertex == searchvertex)) {
    /* Cache hit; we're done. */
    return cache[hash].mylinkring;
  }
  /* Is cache entry at the odd location (adding one) a hit? */
  if ((cache[hash + 1].mylink2d == link) &&
      (cache[hash + 1].myvertex == searchvertex)) {
    /* Cache hit. */
    linkring = cache[hash + 1].mylinkring;
  } else {
    /* Cache miss.  Find the link ring the slow way. */
    linkring = link2dfindringnocache(pool, link, groundtag, searchvertex,
                                     (tag *) NULL);
  }

  /* Make the sought link ring be the first (even) entry at this cache      */
  /*   location, and move whatever is currently there into the second (odd) */
  /*   entry.  The former second entry will no longer be in the cache.      */
  cache[hash + 1].mylink2d = cache[hash].mylink2d;
  cache[hash + 1].myvertex = cache[hash].myvertex;
  cache[hash + 1].mylinkring = cache[hash].mylinkring;
  cache[hash].mylink2d = link;
  cache[hash].myvertex = searchvertex;
  cache[hash].mylinkring = linkring;

  return linkring;
}

/*****************************************************************************/
/*                                                                           */
/*  link2dinsertvertexnocache()   Insert a vertex into a 2D link, associated */
/*                                with a link ring.                          */
/*                                                                           */
/*  This procedure does not check whether the vertex `newvertex' is already  */
/*  in the link.  It's the client's responsibility not to call this          */
/*  procedure if the vertex is already there.  If it might be there or might */
/*  not, call link2dfindring() first, or use link2dfindinsert() instead.     */
/*                                                                           */
/*  pool:  The proxipool that the link was allocated from, and that new      */
/*    molecules will be allocated from.                                      */
/*  linkhead:  Tag for the first molecule in the link.                       */
/*  linktail:  Tag for the last molecule in the link.  Passed by pointer,    */
/*    and may be modified on return.                                         */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  newvertex:  The new vertex to insert into the link.                      */
/*  linkring:  The link ring associated with the vertex `newvertex'.         */
/*                                                                           */
/*****************************************************************************/

void link2dinsertvertexnocache(struct proxipool *pool,
                               tag linkhead,
                               tag *linktail,
                               tag groundtag,
                               tag newvertex,
                               tag linkring)
{
  struct linkpossmall position;
  int numatoms;
  int starttagflag;
  char newtextatoms[2 * COMPRESSEDTAGLENGTH];

  if ((linkhead >= STOP) || (*linktail >= STOP) ||
      (newvertex == STOP) || (linkring >= STOP)) {
    /* Invalid parameters. */
    return;
  }

  /* Start at the last molecule. */
  position.moleculetag = *linktail;
  position.nextmoleculetag = STOP;
  /* Convert the molecule's tag to a pointer. */
  position.cule = (molecule) proxipooltag2object(pool, position.moleculetag);
#ifdef SELF_CHECK
  if (position.cule == (molecule) NULL) {
    printf("Internal error in link2dinsertvertexnocache():\n");
    printf("  Molecule tag indexes a NULL pointer.\n");
    internalerror();
  }
#endif /* SELF_CHECK */
  if (position.cule[MOLECULESIZE - 1] != (char) STOP) {
    /* Oops.  `linktail' isn't really a tail molecule. */
    printf("Internal error in link2dinsertvertexnocache():\n");
    printf("  Parameter `linktail' is not the tail of a list.\n");
    internalerror();
  }
  position.lasttextindex = MOLECULESIZE - 2;

  /* Search for the end of the atoms in the link.  If the head and tail   */
  /*   molecules are the same, the list might be empty, in which case the */
  /*   very first atom is STOP.  Otherwise, the tail molecule must begin  */
  /*   with at least one non-STOP atom (this is an invariant of the link  */
  /*   data structure), so we check the stop bit of the first atom to see */
  /*   whether the second atom might be a STOP atom.                      */
  if (linkhead == *linktail) {
    starttagflag = 1;
    position.textindex = 0;
  } else {
    starttagflag = position.cule[0] < (char) 0;
    position.textindex = 1;
  }
  /* Loop through the atoms, looking for a STOP tag. */
  while ((position.cule[position.textindex] != (char) STOP) ||
         !starttagflag) {
    if (position.textindex >= MOLECULESIZE - 1) {
      /* Oops.  The end of the last tag is missing from the last molecule. */
      printf("Internal error in link2dinsertvertexnocache():\n");
      printf("  Link ring not properly terminated.\n");
      internalerror();
    }
    starttagflag = position.cule[position.textindex] < (char) 0;
    position.textindex++;
  }

  numatoms = linkringtagcompress(linkhead, linkring, newtextatoms);
  numatoms += linkringtagcompress(groundtag, newvertex,
                                  &newtextatoms[numatoms]);
  *linktail = linkringinsertatoms(pool, &position, numatoms, newtextatoms,
                                  proxipooltag2allocindex(pool, linkhead));
}

/*****************************************************************************/
/*                                                                           */
/*  link2dinsertvertex()   Insert a vertex into a 2D link, associated with   */
/*                         a link ring.                                      */
/*                                                                           */
/*  This procedure does not check whether the vertex `newvertex' is already  */
/*  in the link.  It's the client's responsibility not to call this          */
/*  procedure if the vertex is already there.  If you're not sure it's not   */
/*  already in the link, use link2dfindinsert() instead, or call             */
/*  link2dfindring() first.                                                  */
/*                                                                           */
/*  This procedure updates the cache to reflect the insertion, then calls    */
/*  link2dinsertvertexnocache() to perform the insertion.                    */
/*                                                                           */
/*  pool:  The proxipool that the link was allocated from, and that new      */
/*    molecules will be allocated from.                                      */
/*  cache:  An (optional) cache that will be updated by the insertion.       */
/*  linkhead:  Tag for the first molecule in the link.                       */
/*  linktail:  Tag for the last molecule in the link.  Passed by pointer,    */
/*    and modified on return.                                                */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  newvertex:  The new vertex to insert into the link.                      */
/*  linkring:  The link ring associated with the vertex `newvertex'.         */
/*                                                                           */
/*****************************************************************************/

void link2dinsertvertex(struct proxipool *pool,
                        link2dcache cache,
                        tag linkhead,
                        tag *linktail,
                        tag groundtag,
                        tag newvertex,
                        tag linkring)
{
  int hash;

  if ((linkhead >= STOP) || (*linktail >= STOP) ||
      (newvertex == STOP) || (linkring >= STOP)) {
    /* Invalid parameters. */
    return;
  }

  if (cache != NULL) {
    hash = (LINK2DPRIME * linkhead * linkhead + 2u * newvertex) &
           (LINK2DCACHESIZE - 2);
    if ((cache[hash].mylink2d != linkhead) ||
        (cache[hash].myvertex != newvertex)) {
      cache[hash + 1].mylink2d = cache[hash].mylink2d;
      cache[hash + 1].myvertex = cache[hash].myvertex;
      cache[hash + 1].mylinkring = cache[hash].mylinkring;
      cache[hash].mylink2d = linkhead;
      cache[hash].myvertex = newvertex;
    }
    cache[hash].mylinkring = linkring;
  }

  return link2dinsertvertexnocache(pool, linkhead, linktail, groundtag,
                                   newvertex, linkring);
}

/*****************************************************************************/
/*                                                                           */
/*  link2dfindinsert()   Return the link ring associated with a vertex in a  */
/*                       2D link.  If the vertex is not in the link, create  */
/*                       an empty link ring for it and add it to the link.   */
/*                                                                           */
/*  pool:  The proxipool that the link was allocated from, and that new      */
/*    molecules will be allocated from.                                      */
/*  cache:  An (optional) cache that may speed up the lookup, and will be    */
/*    updated if the vertex is inserted.                                     */
/*  linkhead:  Tag for the first molecule in the link.                       */
/*  linktail:  Tag for the last molecule in the link.  Passed by pointer,    */
/*    and may be modified on return.                                         */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  searchvertex:  The tag of the vertex to search for, and possibly insert. */
/*                                                                           */
/*  Returns the link ring associated with `searchvertex' (or STOP if         */
/*    `linkhead' isn't a legal tag--namely, if it's STOP or GHOSTVERTEX).    */
/*                                                                           */
/*****************************************************************************/

tag link2dfindinsert(struct proxipool *pool,
                     link2dcache cache,
                     tag linkhead,
                     tag *linktail,
                     tag groundtag,
                     tag searchvertex)
{
  tag linkring;

  if (linkhead >= STOP) {
    /* Not a link. */
    return STOP;
  }

  linkring = link2dfindring(pool, cache, linkhead, groundtag, searchvertex);
  if (linkring == STOP) {
    linkring = linkringnew(pool, proxipooltag2allocindex(pool, linkhead));
    link2dinsertvertex(pool, cache, linkhead, linktail, groundtag,
                       searchvertex, linkring);
  }

  return linkring;
}

/*****************************************************************************/
/*                                                                           */
/*  link2ddeletevertexnocache()   Delete a vertex from a 2D link.  Also      */
/*                                returns the link ring associated with the  */
/*                                vertex.                                    */
/*                                                                           */
/*  This procedure does not free the link ring's molecules.                  */
/*                                                                           */
/*  pool:  The proxipool that the link was allocated from.                   */
/*  linkhead:  Tag for the first molecule in the link.                       */
/*  linktail:  Tag for the last molecule in the link.  Passed by pointer,    */
/*    and may be modified on return.                                         */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  deletevertex:  The tag of the vertex to delete.                          */
/*                                                                           */
/*  Returns the tag of the link ring associated with `deletevertex' if       */
/*    `deletevertex' is in the link (in which case it is deleted from the    */
/*    link); STOP otherwise.                                                 */
/*                                                                           */
/*****************************************************************************/

tag link2ddeletevertexnocache(struct proxipool *pool,
                              tag linkhead,
                              tag *linktail,
                              tag groundtag,
                              tag deletevertex)
{
  struct linkpossmall position;
  molecule cule;
  tag nextmoleculetag;
  tag moleculetag;
  tag texttag;
  int textatoms;
  int vertexatoms;
  int atomindex;
  int lasttextindex;
  int vertextagflag;
  int firstflag;
  int matchflag;
  char nowatom;

  if (linkhead >= STOP) {
    /* Not a link. */
    return STOP;
  }

  texttag = 0;
  textatoms = 0;
  vertexatoms = 0;
  /* Start at the first molecule. */
  nextmoleculetag = linkhead;
  /* Set to 1 while reading a vertex tag; 0 when reading a link ring tag. */
  vertextagflag = 1;
  /* Set to 1 during the first iteration of the "do" loop. */
  firstflag = 1;
  matchflag = 0;

  /* Loop through the linked list of molecules. */
  do {
    /* Convert the molecule's tag to a pointer. */
    cule = (molecule) proxipooltag2object(pool, nextmoleculetag);
#ifdef SELF_CHECK
    if (cule == (molecule) NULL) {
      printf("Internal error in link2ddeletevertexnocache():\n");
      printf("  Molecule tag indexes a NULL pointer.\n");
      internalerror();
    }
#endif /* SELF_CHECK */
    moleculetag = nextmoleculetag;
    /* Read the "next molecule tag". */
    linkringreadtag(moleculetag, cule, lasttextindex, nextmoleculetag, nowatom,
                    "Internal error in link2ddeletevertexnocache():\n");
    if (firstflag) {
      /* Position to delete atoms from the beginning of the linked list. */
      position.cule = cule;
      position.moleculetag = moleculetag;
      position.textindex = 0;
      position.lasttextindex = lasttextindex;
      position.nextmoleculetag = nextmoleculetag;
      firstflag = 0;
    }

    atomindex = 0;
    /* Loop through the atoms, stopping at the "next molecule tag". */
    while (atomindex <= lasttextindex) {
      nowatom = cule[atomindex];
      /* Append the atom to the text tag. */
      texttag = (texttag << 7) + (nowatom & (char) 127);
      textatoms++;
      atomindex++;

      /* Is this the last atom in the compressed tag? */
      if (nowatom < (char) 0) {
        /* Yes; we have an uncompressed tag now.  What tag is it? */
        if ((nowatom == (char) STOP) && (textatoms == 1)) {
          /* STOP tag.  Exit the inner loop early; go on to next molecule. */
          break;
        } else if (vertextagflag) {
          /* Is this the vertex we're searching for? */
          if ((nowatom == (char) GHOSTVERTEX) && (textatoms == 1)) {
            /* Ghost vertex. */
            matchflag = deletevertex == GHOSTVERTEX;
          } else {
            /* Use the ground tag to supply the high-order bits of the */
            /*   vertex tag.                                           */
            matchflag =
              deletevertex ==
              texttag + ((groundtag >> (7 * textatoms)) << (7 * textatoms));
          }
          vertexatoms = textatoms;
        } else if (matchflag) {
          /* Delete the vertex and its link ring. */
          *linktail = linkringdeleteatoms(pool, &position,
                                          vertexatoms + textatoms);
          /* Use the link tag to supply the high-order bits of the */
          /*   link ring.  Return the latter.                      */
          return texttag + ((linkhead >> (7 * textatoms)) << (7 * textatoms));
        } else {
          /* Store the position of the beginning of the next compressed tag, */
          /*   in case the vertex starting here proves to be `deletevertex'. */
          position.cule = cule;
          position.moleculetag = moleculetag;
          position.textindex = atomindex;
          position.lasttextindex = lasttextindex;
          position.nextmoleculetag = nextmoleculetag;
        }

        /* Prepare to read another tag. */
        texttag = 0;
        textatoms = 0;
        /* Alternate between reading vertex tags and link ring tags. */
        vertextagflag = !vertextagflag;
      }
    }
  } while (nextmoleculetag != STOP);

  if (nowatom >= (char) 0) {
    /* Oops.  The end of the last tag is missing from the last molecule. */
    printf("Internal error in link2ddeletevertexnocache():\n");
    printf("  Tag at end of 2D link not properly terminated.\n");
    internalerror();
  }

  /* `deletevertex' is not in the link. */
  return STOP;
}

/*****************************************************************************/
/*                                                                           */
/*  link2ddeletevertex()   Delete a vertex from a 2D link.  Also returns the */
/*                         link ring associated with the vertex.             */
/*                                                                           */
/*  This procedure does not free the link ring's molecules.                  */
/*                                                                           */
/*  This procedure updates the cache to reflect the deletion, then calls     */
/*  link2ddeletevertexnocache() to perform the deletion (unless the first    */
/*  cache entry says that the vertex is not present).                        */
/*                                                                           */
/*  pool:  The proxipool that the link was allocated from.                   */
/*  cache:  An (optional) cache that will be updated by the deletion.        */
/*  linkhead:  Tag for the first molecule in the link.                       */
/*  linktail:  Tag for the last molecule in the link.  Passed by pointer,    */
/*    and may be modified on return.                                         */
/*  groundtag:  The ground tag relative to which the vertices are            */
/*    decompressed.                                                          */
/*  deletevertex:  The tag of the vertex to delete.                          */
/*                                                                           */
/*  Returns the tag of the link ring associated with `deletevertex' if       */
/*    `deletevertex' is in the link (in which case it is deleted from the    */
/*    link); STOP otherwise.                                                 */
/*                                                                           */
/*****************************************************************************/

tag link2ddeletevertex(struct proxipool *pool,
                       link2dcache cache,
                       tag linkhead,
                       tag *linktail,
                       tag groundtag,
                       tag deletevertex)
{
  int hash;

  if (linkhead >= STOP) {
    /* Not a link. */
    return STOP;
  }

  if (cache != NULL) {
    hash = (LINK2DPRIME * linkhead * linkhead + 2u * deletevertex) &
           (LINK2DCACHESIZE - 2);
    if ((cache[hash].mylink2d == linkhead) &&
        (cache[hash].myvertex == deletevertex)) {
      if (cache[hash].mylinkring == STOP) {
        return STOP;
      }
    } else {
      cache[hash + 1].mylink2d = cache[hash].mylink2d;
      cache[hash + 1].myvertex = cache[hash].myvertex;
      cache[hash + 1].mylinkring = cache[hash].mylinkring;
      cache[hash].mylink2d = linkhead;
      cache[hash].myvertex = deletevertex;
    }
    cache[hash].mylinkring = STOP;
  }

  return link2ddeletevertexnocache(pool, linkhead, linktail, groundtag,
                                   deletevertex);
}

/**                                                                         **/
/**                                                                         **/
/********* 2D link/triangulation representation routines end here    *********/


/********* Geometric primitives begin here                           *********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  Robust geometric predicates using adaptive precision floating-point      */
/*  arithmetic                                                               */
/*                                                                           */
/*  The adaptive exact arithmetic geometric predicates implemented herein    */
/*  are described in detail in my paper, "Adaptive Precision Floating-Point  */
/*  Arithmetic and Fast Robust Geometric Predicates."  See the header for a  */
/*  full citation.                                                           */
/*                                                                           */
/*****************************************************************************/

/*  Which of the following two methods of finding the absolute values is     */
/*  fastest is compiler-dependent.  A few compilers can inline and optimize  */
/*  the fabs() call; but most will incur the overhead of a function call,    */
/*  which is disastrously slow.  A faster way on IEEE machines might be to   */
/*  mask the appropriate bit.                                                */

#define Absolute(a)  ((a) >= 0.0 ? (a) : -(a))
/* #define Absolute(a)  fabs(a) */

/*  Many of the operations are broken up into two pieces--a main part that   */
/*  performs an approximate operation, and a "tail" that computes the        */
/*  roundoff error of that operation.                                        */
/*                                                                           */
/*  The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(),   */
/*  Split(), and Two_Product() are all implemented as described in the       */
/*  reference.  Each of these macros requires certain variables to be        */
/*  defined in the calling routine.  The variables `bvirt', `c', `abig',     */
/*  `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because    */
/*  they store the result of an operation that may incur roundoff error.     */
/*  The input parameter `x' (or the highest numbered `x_' parameter) must    */
/*  also be declared `INEXACT'.                                              */

#define Fast_Two_Sum_Tail(a, b, x, y) \
  bvirt = x - a; \
  y = b - bvirt

#define Fast_Two_Sum(a, b, x, y) \
  x = (starreal) (a + b); \
  Fast_Two_Sum_Tail(a, b, x, y)

#define Two_Sum_Tail(a, b, x, y) \
  bvirt = (starreal) (x - a); \
  avirt = x - bvirt; \
  bround = b - bvirt; \
  around = a - avirt; \
  y = around + bround

#define Two_Sum(a, b, x, y) \
  x = (starreal) (a + b); \
  Two_Sum_Tail(a, b, x, y)

#define Two_Diff_Tail(a, b, x, y) \
  bvirt = (starreal) (a - x); \
  avirt = x + bvirt; \
  bround = bvirt - b; \
  around = a - avirt; \
  y = around + bround

#define Two_Diff(a, b, x, y) \
  x = (starreal) (a - b); \
  Two_Diff_Tail(a, b, x, y)

#define Split(a, ahi, alo) \
  c = (starreal) (splitter * a); \
  abig = (starreal) (c - a); \
  ahi = c - abig; \
  alo = a - ahi

#define Two_Product_Tail(a, b, x, y) \
  Split(a, ahi, alo); \
  Split(b, bhi, blo); \
  err1 = x - (ahi * bhi); \
  err2 = err1 - (alo * bhi); \
  err3 = err2 - (ahi * blo); \
  y = (alo * blo) - err3

#define Two_Product(a, b, x, y) \
  x = (starreal) (a * b); \
  Two_Product_Tail(a, b, x, y)

/*  Two_Product_Presplit() is Two_Product() where one of the inputs has      */
/*  already been split.  Avoids redundant splitting.                         */

#define Two_Product_Presplit(a, b, bhi, blo, x, y) \
  x = (starreal) (a * b); \
  Split(a, ahi, alo); \
  err1 = x - (ahi * bhi); \
  err2 = err1 - (alo * bhi); \
  err3 = err2 - (ahi * blo); \
  y = (alo * blo) - err3

/*  Square() can be done more quickly than Two_Product().                    */

#define Square_Tail(a, x, y) \
  Split(a, ahi, alo); \
  err1 = x - (ahi * ahi); \
  err3 = err1 - ((ahi + ahi) * alo); \
  y = (alo * alo) - err3

#define Square(a, x, y) \
  x = (starreal) (a * a); \
  Square_Tail(a, x, y)

/*  Macros for summing expansions of various fixed lengths.  These are all   */
/*  unrolled versions of Expansion_Sum().                                    */

#define Two_One_Sum(a1, a0, b, x2, x1, x0) \
  Two_Sum(a0, b , _i, x0); \
  Two_Sum(a1, _i, x2, x1)

#define Two_One_Diff(a1, a0, b, x2, x1, x0) \
  Two_Diff(a0, b , _i, x0); \
  Two_Sum( a1, _i, x2, x1)

#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \
  Two_One_Sum(a1, a0, b0, _j, _0, x0); \
  Two_One_Sum(_j, _0, b1, x3, x2, x1)

#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \
  Two_One_Diff(a1, a0, b0, _j, _0, x0); \
  Two_One_Diff(_j, _0, b1, x3, x2, x1)

#define Four_One_Sum(a3, a2, a1, a0, b, x4, x3, x2, x1, x0) \
  Two_One_Sum(a1, a0, b , _j, x1, x0); \
  Two_One_Sum(a3, a2, _j, x4, x3, x2)

#define Four_Two_Sum(a3, a2, a1, a0, b1, b0, x5, x4, x3, x2, x1, x0) \
  Four_One_Sum(a3, a2, a1, a0, b0, _k, _2, _1, _0, x0); \
  Four_One_Sum(_k, _2, _1, _0, b1, x5, x4, x3, x2, x1)

#define Four_Four_Sum(a3, a2, a1, a0, b4, b3, b1, b0, x7, x6, x5, x4, x3, x2, \
                      x1, x0) \
  Four_Two_Sum(a3, a2, a1, a0, b1, b0, _l, _2, _1, _0, x1, x0); \
  Four_Two_Sum(_l, _2, _1, _0, b4, b3, x7, x6, x5, x4, x3, x2)

#define Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b, x8, x7, x6, x5, x4, \
                      x3, x2, x1, x0) \
  Four_One_Sum(a3, a2, a1, a0, b , _j, x3, x2, x1, x0); \
  Four_One_Sum(a7, a6, a5, a4, _j, x8, x7, x6, x5, x4)

#define Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, x9, x8, x7, \
                      x6, x5, x4, x3, x2, x1, x0) \
  Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b0, _k, _6, _5, _4, _3, _2, \
                _1, _0, x0); \
  Eight_One_Sum(_k, _6, _5, _4, _3, _2, _1, _0, b1, x9, x8, x7, x6, x5, x4, \
                x3, x2, x1)

#define Eight_Four_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b4, b3, b1, b0, x11, \
                       x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0) \
  Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, _l, _6, _5, _4, _3, \
                _2, _1, _0, x1, x0); \
  Eight_Two_Sum(_l, _6, _5, _4, _3, _2, _1, _0, b4, b3, x11, x10, x9, x8, \
                x7, x6, x5, x4, x3, x2)

/*  Macro for multiplying a two-component expansion by a single component.   */

#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \
  Split(b, bhi, blo); \
  Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \
  Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \
  Two_Sum(_i, _0, _k, x1); \
  Fast_Two_Sum(_j, _k, x3, x2)

/*****************************************************************************/
/*                                                                           */
/*  primitivesinit()   Initialize the variables used for exact arithmetic.   */
/*                                                                           */
/*  `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in   */
/*  floating-point arithmetic.  `epsilon' bounds the relative roundoff       */
/*  error.  It is used for floating-point error analysis.                    */
/*                                                                           */
/*  `splitter' is used to split floating-point numbers into two half-        */
/*  length significands for exact multiplication.                            */
/*                                                                           */
/*  I imagine that a highly optimizing compiler might be too smart for its   */
/*  own good, and somehow cause this routine to fail, if it pretends that    */
/*  floating-point arithmetic is too much like real arithmetic.              */
/*                                                                           */
/*  Don't change this routine unless you really understand it.               */
/*                                                                           */
/*****************************************************************************/

void primitivesinit(void)
{
  starreal half;
  starreal check, lastcheck;
  int every_other;
#ifdef LINUX
  int cword;
#endif /* LINUX */

#ifdef CPU86
#ifdef SINGLE
  _control87(_PC_24, _MCW_PC); /* Set FPU control word for single precision. */
#else /* not SINGLE */
  _control87(_PC_53, _MCW_PC); /* Set FPU control word for double precision. */
#endif /* not SINGLE */
#endif /* CPU86 */
#ifdef LINUX
#ifdef SINGLE
  /*  cword = 4223; */
  cword = 4210;                 /* set FPU control word for single precision */
#else /* not SINGLE */
  /*  cword = 4735; */
  cword = 4722;                 /* set FPU control word for double precision */
#endif /* not SINGLE */
  _FPU_SETCW(cword);
#endif /* LINUX */

  every_other = 1;
  half = 0.5;
  epsilon = 1.0;
  splitter = 1.0;
  check = 1.0;
  /* Repeatedly divide `epsilon' by two until it is too small to add to      */
  /*   one without causing roundoff.  (Also check if the sum is equal to     */
  /*   the previous sum, for machines that round up instead of using exact   */
  /*   rounding.  Not that these routines will work on such machines.)       */
  do {
    lastcheck = check;
    epsilon *= half;
    if (every_other) {
      splitter *= 2.0;
    }
    every_other = !every_other;
    check = 1.0 + epsilon;
  } while ((check != 1.0) && (check != lastcheck));
  splitter += 1.0;
  /* Error bounds for orientation and insphere tests. */
  resulterrbound = (3.0 + 8.0 * epsilon) * epsilon;
  o2derrboundA = (3.0 + 16.0 * epsilon) * epsilon;
  o2derrboundB = (2.0 + 12.0 * epsilon) * epsilon;
  o2derrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon;
  o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon;
  o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon;
  o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon;
  isperrboundA = (16.0 + 224.0 * epsilon) * epsilon;
  isperrboundB = (5.0 + 72.0 * epsilon) * epsilon;
  isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon;
}

/*****************************************************************************/
/*                                                                           */
/*  fast_expansion_sum_zeroelim()   Sum two expansions, eliminating zero     */
/*                                  components from the output expansion.    */
/*                                                                           */
/*  Sets h = e + f.  See my Robust Predicates paper for details.             */
/*                                                                           */
/*  h cannot be e or f.                                                      */
/*                                                                           */
/*  If round-to-even is used (as with IEEE 754), maintains the strongly      */
/*  nonoverlapping property.  (That is, if e is strongly nonoverlapping, h   */
/*  will be also.)  Does NOT maintain the nonoverlapping or nonadjacent      */
/*  properties.                                                              */
/*                                                                           */
/*****************************************************************************/

int fast_expansion_sum_zeroelim(int elen,
                                starreal *e,
                                int flen,
                                starreal *f,
                                starreal *h)
{
  starreal Q;
  INEXACT starreal Qnew;
  INEXACT starreal hh;
  INEXACT starreal bvirt;
  starreal avirt, bround, around;
  int eindex, findex, hindex;
  starreal enow, fnow;

  enow = e[0];
  fnow = f[0];
  eindex = findex = 0;
  if ((fnow > enow) == (fnow > -enow)) {
    Q = enow;
    enow = e[++eindex];
  } else {
    Q = fnow;
    fnow = f[++findex];
  }
  hindex = 0;
  if ((eindex < elen) && (findex < flen)) {
    if ((fnow > enow) == (fnow > -enow)) {
      Fast_Two_Sum(enow, Q, Qnew, hh);
      enow = e[++eindex];
    } else {
      Fast_Two_Sum(fnow, Q, Qnew, hh);
      fnow = f[++findex];
    }
    Q = Qnew;
    if (hh != 0.0) {
      h[hindex++] = hh;
    }
    while ((eindex < elen) && (findex < flen)) {
      if ((fnow > enow) == (fnow > -enow)) {
        Two_Sum(Q, enow, Qnew, hh);
        enow = e[++eindex];
      } else {
        Two_Sum(Q, fnow, Qnew, hh);
        fnow = f[++findex];
      }
      Q = Qnew;
      if (hh != 0.0) {
        h[hindex++] = hh;
      }
    }
  }
  while (eindex < elen) {
    Two_Sum(Q, enow, Qnew, hh);
    enow = e[++eindex];
    Q = Qnew;
    if (hh != 0.0) {
      h[hindex++] = hh;
    }
  }
  while (findex < flen) {
    Two_Sum(Q, fnow, Qnew, hh);
    fnow = f[++findex];
    Q = Qnew;
    if (hh != 0.0) {
      h[hindex++] = hh;
    }
  }
  if ((Q != 0.0) || (hindex == 0)) {
    h[hindex++] = Q;
  }
  return hindex;
}

/*****************************************************************************/
/*                                                                           */
/*  scale_expansion_zeroelim()   Multiply an expansion by a scalar,          */
/*                               eliminating zero components from the        */
/*                               output expansion.                           */
/*                                                                           */
/*  Sets h = be.  See my Robust Predicates paper for details.                */
/*                                                                           */
/*  e and h cannot be the same.                                              */
/*                                                                           */
/*  Maintains the nonoverlapping property.  If round-to-even is used (as     */
/*  with IEEE 754), maintains the strongly nonoverlapping and nonadjacent    */
/*  properties as well.  (That is, if e has one of these properties, so      */
/*  will h.)                                                                 */
/*                                                                           */
/*****************************************************************************/

int scale_expansion_zeroelim(int elen,
                             starreal *e,
                             starreal b,
                             starreal *h)
{
  INEXACT starreal Q, sum;
  starreal hh;
  INEXACT starreal product1;
  starreal product0;
  int eindex, hindex;
  starreal enow;
  INEXACT starreal bvirt;
  starreal avirt, bround, around;
  INEXACT starreal c;
  INEXACT starreal abig;
  starreal ahi, alo, bhi, blo;
  starreal err1, err2, err3;

  Split(b, bhi, blo);
  Two_Product_Presplit(e[0], b, bhi, blo, Q, hh);
  hindex = 0;
  if (hh != 0) {
    h[hindex++] = hh;
  }
  for (eindex = 1; eindex < elen; eindex++) {
    enow = e[eindex];
    Two_Product_Presplit(enow, b, bhi, blo, product1, product0);
    Two_Sum(Q, product0, sum, hh);
    if (hh != 0) {
      h[hindex++] = hh;
    }
    Fast_Two_Sum(product1, sum, Q, hh);
    if (hh != 0) {
      h[hindex++] = hh;
    }
  }
  if ((Q != 0.0) || (hindex == 0)) {
    h[hindex++] = Q;
  }
  return hindex;
}

/*****************************************************************************/
/*                                                                           */
/*  estimate()   Produce a one-word estimate of an expansion's value.        */
/*                                                                           */
/*  See my Robust Predicates paper for details.                              */
/*                                                                           */
/*****************************************************************************/

starreal estimate(int elen,
                  starreal *e)
{
  starreal Q;
  int eindex;

  Q = e[0];
  for (eindex = 1; eindex < elen; eindex++) {
    Q += e[eindex];
  }
  return Q;
}

/*****************************************************************************/
/*                                                                           */
/*  orient2d()   Calculate the determinant | ax ay 1 |                       */
/*                                         | bx by 1 |                       */
/*                                         | cx cy 1 |                       */
/*                                                                           */
/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
/*  determinant is computed adaptively, in the sense that exact arithmetic   */
/*  is used only to the degree it is needed to ensure that the returned      */
/*  value has the correct sign.  Hence, this function is usually quite fast, */
/*  but will run more slowly when the input points are collinear or nearly   */
/*  so.                                                                      */
/*                                                                           */
/*  See my Robust Predicates paper for details.                              */
/*                                                                           */
/*****************************************************************************/

starreal orient2dadapt(starreal ax,
                       starreal ay,
                       starreal bx,
                       starreal by,
                       starreal cx,
                       starreal cy,
                       starreal detsum)
{
  INEXACT starreal acx, acy, bcx, bcy;
  starreal acxtail, acytail, bcxtail, bcytail;
  INEXACT starreal detleft, detright;
  starreal detlefttail, detrighttail;
  starreal det, errbound;
  starreal B[4], C1[8], C2[12], D[16];
  INEXACT starreal B3;
  int C1length, C2length, Dlength;
  starreal u[4];
  INEXACT starreal u3;
  INEXACT starreal s1, t1;
  starreal s0, t0;

  INEXACT starreal bvirt;
  starreal avirt, bround, around;
  INEXACT starreal c;
  INEXACT starreal abig;
  starreal ahi, alo, bhi, blo;
  starreal err1, err2, err3;
  INEXACT starreal _i, _j;
  starreal _0;

  acx = (starreal) (ax - cx);
  bcx = (starreal) (bx - cx);
  acy = (starreal) (ay - cy);
  bcy = (starreal) (by - cy);

  Two_Product(acx, bcy, detleft, detlefttail);
  Two_Product(acy, bcx, detright, detrighttail);

  Two_Two_Diff(detleft, detlefttail, detright, detrighttail,
               B3, B[2], B[1], B[0]);
  B[3] = B3;

  det = estimate(4, B);
  errbound = o2derrboundB * detsum;
  if ((det >= errbound) || (-det >= errbound)) {
    return det;
  }

  Two_Diff_Tail(ax, cx, acx, acxtail);
  Two_Diff_Tail(bx, cx, bcx, bcxtail);
  Two_Diff_Tail(ay, cy, acy, acytail);
  Two_Diff_Tail(by, cy, bcy, bcytail);

  if ((acxtail == 0.0) && (acytail == 0.0) &&
      (bcxtail == 0.0) && (bcytail == 0.0)) {
    return det;
  }

  errbound = o2derrboundC * detsum + resulterrbound * Absolute(det);
  det += (acx * bcytail + bcy * acxtail) -
         (acy * bcxtail + bcx * acytail);
  if ((det >= errbound) || (-det >= errbound)) {
    return det;
  }

  Two_Product(acxtail, bcy, s1, s0);
  Two_Product(acytail, bcx, t1, t0);
  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
  u[3] = u3;
  C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1);

  Two_Product(acx, bcytail, s1, s0);
  Two_Product(acy, bcxtail, t1, t0);
  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
  u[3] = u3;
  C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2);

  Two_Product(acxtail, bcytail, s1, s0);
  Two_Product(acytail, bcxtail, t1, t0);
  Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
  u[3] = u3;
  Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D);

  return(D[Dlength - 1]);
}

starreal orient2d(struct behavior *b,
                  starreal ax,
                  starreal ay,
                  starreal bx,
                  starreal by,
                  starreal cx,
                  starreal cy)
{
  starreal detleft, detright, det;
  starreal detsum, errbound;

  detleft = (ax - cx) * (by - cy);
  detright = (ay - cy) * (bx - cx);
  det = detleft - detright;

  if (b->noexact) {
    return det;
  }

  if (detleft > 0.0) {
    if (detright <= 0.0) {
      return det;
    } else {
      detsum = detleft + detright;
    }
  } else if (detleft < 0.0) {
    if (detright >= 0.0) {
      return det;
    } else {
      detsum = -detleft - detright;
    }
  } else {
    return det;
  }

  errbound = o2derrboundA * detsum;
  if ((det >= errbound) || (-det >= errbound)) {
    return det;
  }

  return orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
}

/*****************************************************************************/
/*                                                                           */
/*  orient3d()   Return a positive value if the point pd lies below the      */
/*               plane passing through pa, pb, and pc; "below" is defined so */
/*               that pa, pb, and pc appear in counterclockwise order when   */
/*               viewed from above the plane.  Returns a negative value if   */
/*               pd lies above the plane.  Returns zero if the points are    */
/*               coplanar.  The result is also a rough approximation of six  */
/*               times the signed volume of the tetrahedron defined by the   */
/*               four points.                                                */
/*                                                                           */
/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
/*  result returned is the determinant of a matrix.  This determinant is     */
/*  computed adaptively, in the sense that exact arithmetic is used only to  */
/*  the degree it is needed to ensure that the returned value has the        */
/*  correct sign.  Hence, this function is usually quite fast, but will run  */
/*  more slowly when the input points are coplanar or nearly so.             */
/*                                                                           */
/*  See my Robust Predicates paper for details.                              */
/*                                                                           */
/*****************************************************************************/

starreal orient3dadapt(starreal *pa,
                       starreal *pb,
                       starreal *pc,
                       starreal *pd,
                       starreal permanent)
{
  INEXACT starreal adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz;
  starreal det, errbound;

  INEXACT starreal bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
  starreal bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
  starreal bc[4], ca[4], ab[4];
  INEXACT starreal bc3, ca3, ab3;
  starreal adet[8], bdet[8], cdet[8];
  int alen, blen, clen;
  starreal abdet[16];
  int ablen;
  starreal *finnow, *finother, *finswap;
  starreal fin1[192], fin2[192];
  int finlength;

  starreal adxtail, bdxtail, cdxtail;
  starreal adytail, bdytail, cdytail;
  starreal adztail, bdztail, cdztail;
  INEXACT starreal at_blarge, at_clarge;
  INEXACT starreal bt_clarge, bt_alarge;
  INEXACT starreal ct_alarge, ct_blarge;
  starreal at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4];
  int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen;
  INEXACT starreal bdxt_cdy1, cdxt_bdy1, cdxt_ady1;
  INEXACT starreal adxt_cdy1, adxt_bdy1, bdxt_ady1;
  starreal bdxt_cdy0, cdxt_bdy0, cdxt_ady0;
  starreal adxt_cdy0, adxt_bdy0, bdxt_ady0;
  INEXACT starreal bdyt_cdx1, cdyt_bdx1, cdyt_adx1;
  INEXACT starreal adyt_cdx1, adyt_bdx1, bdyt_adx1;
  starreal bdyt_cdx0, cdyt_bdx0, cdyt_adx0;
  starreal adyt_cdx0, adyt_bdx0, bdyt_adx0;
  starreal bct[8], cat[8], abt[8];
  int bctlen, catlen, abtlen;
  INEXACT starreal bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1;
  INEXACT starreal adxt_cdyt1, adxt_bdyt1, bdxt_adyt1;
  starreal bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0;
  starreal adxt_cdyt0, adxt_bdyt0, bdxt_adyt0;
  starreal u[4], v[12], w[16];
  INEXACT starreal u3;
  int vlength, wlength;
  starreal negate;

  INEXACT starreal bvirt;
  starreal avirt, bround, around;
  INEXACT starreal c;
  INEXACT starreal abig;
  starreal ahi, alo, bhi, blo;
  starreal err1, err2, err3;
  INEXACT starreal _i, _j, _k;
  starreal _0;

  adx = (starreal) (pa[0] - pd[0]);
  bdx = (starreal) (pb[0] - pd[0]);
  cdx = (starreal) (pc[0] - pd[0]);
  ady = (starreal) (pa[1] - pd[1]);
  bdy = (starreal) (pb[1] - pd[1]);
  cdy = (starreal) (pc[1] - pd[1]);
  adz = (starreal) (pa[2] - pd[2]);
  bdz = (starreal) (pb[2] - pd[2]);
  cdz = (starreal) (pc[2] - pd[2]);

  Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
  Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
  Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
  bc[3] = bc3;
  alen = scale_expansion_zeroelim(4, bc, adz, adet);

  Two_Product(cdx, ady, cdxady1, cdxady0);
  Two_Product(adx, cdy, adxcdy1, adxcdy0);
  Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
  ca[3] = ca3;
  blen = scale_expansion_zeroelim(4, ca, bdz, bdet);

  Two_Product(adx, bdy, adxbdy1, adxbdy0);
  Two_Product(bdx, ady, bdxady1, bdxady0);
  Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
  ab[3] = ab3;
  clen = scale_expansion_zeroelim(4, ab, cdz, cdet);

  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
  finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);

  det = estimate(finlength, fin1);
  errbound = o3derrboundB * permanent;
  if ((det >= errbound) || (-det >= errbound)) {
    return det;
  }

  Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
  Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
  Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
  Two_Diff_Tail(pa[1], pd[1], ady, adytail);
  Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
  Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
  Two_Diff_Tail(pa[2], pd[2], adz, adztail);
  Two_Diff_Tail(pb[2], pd[2], bdz, bdztail);
  Two_Diff_Tail(pc[2], pd[2], cdz, cdztail);

  if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) &&
      (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0) &&
      (adztail == 0.0) && (bdztail == 0.0) && (cdztail == 0.0)) {
    return det;
  }

  errbound = o3derrboundC * permanent + resulterrbound * Absolute(det);
  det += (adz * ((bdx * cdytail + cdy * bdxtail)
                 - (bdy * cdxtail + cdx * bdytail))
          + adztail * (bdx * cdy - bdy * cdx))
       + (bdz * ((cdx * adytail + ady * cdxtail)
                 - (cdy * adxtail + adx * cdytail))
          + bdztail * (cdx * ady - cdy * adx))
       + (cdz * ((adx * bdytail + bdy * adxtail)
                 - (ady * bdxtail + bdx * adytail))
          + cdztail * (adx * bdy - ady * bdx));
  if ((det >= errbound) || (-det >= errbound)) {
    return det;
  }

  finnow = fin1;
  finother = fin2;

  if (adxtail == 0.0) {
    if (adytail == 0.0) {
      at_b[0] = 0.0;
      at_blen = 1;
      at_c[0] = 0.0;
      at_clen = 1;
    } else {
      negate = -adytail;
      Two_Product(negate, bdx, at_blarge, at_b[0]);
      at_b[1] = at_blarge;
      at_blen = 2;
      Two_Product(adytail, cdx, at_clarge, at_c[0]);
      at_c[1] = at_clarge;
      at_clen = 2;
    }
  } else {
    if (adytail == 0.0) {
      Two_Product(adxtail, bdy, at_blarge, at_b[0]);
      at_b[1] = at_blarge;
      at_blen = 2;
      negate = -adxtail;
      Two_Product(negate, cdy, at_clarge, at_c[0]);
      at_c[1] = at_clarge;
      at_clen = 2;
    } else {
      Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0);
      Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0);
      Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0,
                   at_blarge, at_b[2], at_b[1], at_b[0]);
      at_b[3] = at_blarge;
      at_blen = 4;
      Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0);
      Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0);
      Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0,
                   at_clarge, at_c[2], at_c[1], at_c[0]);
      at_c[3] = at_clarge;
      at_clen = 4;
    }
  }
  if (bdxtail == 0.0) {
    if (bdytail == 0.0) {
      bt_c[0] = 0.0;
      bt_clen = 1;
      bt_a[0] = 0.0;
      bt_alen = 1;
    } else {
      negate = -bdytail;
      Two_Product(negate, cdx, bt_clarge, bt_c[0]);
      bt_c[1] = bt_clarge;
      bt_clen = 2;
      Two_Product(bdytail, adx, bt_alarge, bt_a[0]);
      bt_a[1] = bt_alarge;
      bt_alen = 2;
    }
  } else {
    if (bdytail == 0.0) {
      Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]);
      bt_c[1] = bt_clarge;
      bt_clen = 2;
      negate = -bdxtail;
      Two_Product(negate, ady, bt_alarge, bt_a[0]);
      bt_a[1] = bt_alarge;
      bt_alen = 2;
    } else {
      Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0);
      Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0);
      Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0,
                   bt_clarge, bt_c[2], bt_c[1], bt_c[0]);
      bt_c[3] = bt_clarge;
      bt_clen = 4;
      Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0);
      Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0);
      Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0,
                  bt_alarge, bt_a[2], bt_a[1], bt_a[0]);
      bt_a[3] = bt_alarge;
      bt_alen = 4;
    }
  }
  if (cdxtail == 0.0) {
    if (cdytail == 0.0) {
      ct_a[0] = 0.0;
      ct_alen = 1;
      ct_b[0] = 0.0;
      ct_blen = 1;
    } else {
      negate = -cdytail;
      Two_Product(negate, adx, ct_alarge, ct_a[0]);
      ct_a[1] = ct_alarge;
      ct_alen = 2;
      Two_Product(cdytail, bdx, ct_blarge, ct_b[0]);
      ct_b[1] = ct_blarge;
      ct_blen = 2;
    }
  } else {
    if (cdytail == 0.0) {
      Two_Product(cdxtail, ady, ct_alarge, ct_a[0]);
      ct_a[1] = ct_alarge;
      ct_alen = 2;
      negate = -cdxtail;
      Two_Product(negate, bdy, ct_blarge, ct_b[0]);
      ct_b[1] = ct_blarge;
      ct_blen = 2;
    } else {
      Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0);
      Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0);
      Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0,
                   ct_alarge, ct_a[2], ct_a[1], ct_a[0]);
      ct_a[3] = ct_alarge;
      ct_alen = 4;
      Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0);
      Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0);
      Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0,
                   ct_blarge, ct_b[2], ct_b[1], ct_b[0]);
      ct_b[3] = ct_blarge;
      ct_blen = 4;
    }
  }

  bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct);
  wlength = scale_expansion_zeroelim(bctlen, bct, adz, w);
  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                          finother);
  finswap = finnow; finnow = finother; finother = finswap;

  catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat);
  wlength = scale_expansion_zeroelim(catlen, cat, bdz, w);
  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                          finother);
  finswap = finnow; finnow = finother; finother = finswap;

  abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt);
  wlength = scale_expansion_zeroelim(abtlen, abt, cdz, w);
  finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                          finother);
  finswap = finnow; finnow = finother; finother = finswap;

  if (adztail != 0.0) {
    vlength = scale_expansion_zeroelim(4, bc, adztail, v);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }
  if (bdztail != 0.0) {
    vlength = scale_expansion_zeroelim(4, ca, bdztail, v);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }
  if (cdztail != 0.0) {
    vlength = scale_expansion_zeroelim(4, ab, cdztail, v);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }

  if (adxtail != 0.0) {
    if (bdytail != 0.0) {
      Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0);
      Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (cdztail != 0.0) {
        Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
    if (cdytail != 0.0) {
      negate = -adxtail;
      Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0);
      Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (bdztail != 0.0) {
        Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
  }
  if (bdxtail != 0.0) {
    if (cdytail != 0.0) {
      Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0);
      Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (adztail != 0.0) {
        Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
    if (adytail != 0.0) {
      negate = -bdxtail;
      Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0);
      Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (cdztail != 0.0) {
        Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
  }
  if (cdxtail != 0.0) {
    if (adytail != 0.0) {
      Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0);
      Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (bdztail != 0.0) {
        Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
    if (bdytail != 0.0) {
      negate = -cdxtail;
      Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0);
      Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adz, u3, u[2], u[1], u[0]);
      u[3] = u3;
      finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                              finother);
      finswap = finnow; finnow = finother; finother = finswap;
      if (adztail != 0.0) {
        Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adztail, u3, u[2], u[1], u[0]);
        u[3] = u3;
        finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u,
                                                finother);
        finswap = finnow; finnow = finother; finother = finswap;
      }
    }
  }

  if (adztail != 0.0) {
    wlength = scale_expansion_zeroelim(bctlen, bct, adztail, w);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }
  if (bdztail != 0.0) {
    wlength = scale_expansion_zeroelim(catlen, cat, bdztail, w);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }
  if (cdztail != 0.0) {
    wlength = scale_expansion_zeroelim(abtlen, abt, cdztail, w);
    finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w,
                                            finother);
    finswap = finnow; finnow = finother; finother = finswap;
  }

  return finnow[finlength - 1];
}

starreal orient3d(struct behavior *b,
                  starreal *pa,
                  starreal *pb,
                  starreal *pc,
                  starreal *pd)
{
  starreal adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz;
  starreal bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
  starreal det;
  starreal permanent, errbound;

  b->orientcount++;

  adx = pa[0] - pd[0];
  bdx = pb[0] - pd[0];
  cdx = pc[0] - pd[0];
  ady = pa[1] - pd[1];
  bdy = pb[1] - pd[1];
  cdy = pc[1] - pd[1];
  adz = pa[2] - pd[2];
  bdz = pb[2] - pd[2];
  cdz = pc[2] - pd[2];

  bdxcdy = bdx * cdy;
  cdxbdy = cdx * bdy;

  cdxady = cdx * ady;
  adxcdy = adx * cdy;

  adxbdy = adx * bdy;
  bdxady = bdx * ady;

  det = adz * (bdxcdy - cdxbdy) 
      + bdz * (cdxady - adxcdy)
      + cdz * (adxbdy - bdxady);

  if (b->noexact) {
    return det;
  }

  permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz)
            + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz)
            + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz);
  errbound = o3derrboundA * permanent;
  if ((det > errbound) || (-det > errbound)) {
    return det;
  }

  return orient3dadapt(pa, pb, pc, pd, permanent);
}

/*****************************************************************************/
/*                                                                           */
/*  insphere()   Return a positive value if the point pe lies inside the     */
/*               sphere passing through pa, pb, pc, and pd; a negative value */
/*               if it lies outside; and zero if the five points are         */
/*               cospherical.  The points pa, pb, pc, and pd must be ordered */
/*               so that they have a positive orientation (as defined by     */
/*               orient3d()), or the sign of the result will be reversed.    */
/*                                                                           */
/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
/*  result returned is the determinant of a matrix.  This determinant is     */
/*  computed adaptively, in the sense that exact arithmetic is used only to  */
/*  the degree it is needed to ensure that the returned value has the        */
/*  correct sign.  Hence, this function is usually quite fast, but will run  */
/*  more slowly when the input points are cospherical or nearly so.          */
/*                                                                           */
/*  See my Robust Predicates paper for details.                              */
/*                                                                           */
/*****************************************************************************/

starreal insphereexact(starreal *pa,
                       starreal *pb,
                       starreal *pc,
                       starreal *pd,
                       starreal *pe)
{
  INEXACT starreal axby1, bxcy1, cxdy1, dxey1, exay1;
  INEXACT starreal bxay1, cxby1, dxcy1, exdy1, axey1;
  INEXACT starreal axcy1, bxdy1, cxey1, dxay1, exby1;
  INEXACT starreal cxay1, dxby1, excy1, axdy1, bxey1;
  starreal axby0, bxcy0, cxdy0, dxey0, exay0;
  starreal bxay0, cxby0, dxcy0, exdy0, axey0;
  starreal axcy0, bxdy0, cxey0, dxay0, exby0;
  starreal cxay0, dxby0, excy0, axdy0, bxey0;
  starreal ab[4], bc[4], cd[4], de[4], ea[4];
  starreal ac[4], bd[4], ce[4], da[4], eb[4];
  starreal temp8a[8], temp8b[8], temp16[16];
  int temp8alen, temp8blen, temp16len;
  starreal abc[24], bcd[24], cde[24], dea[24], eab[24];
  starreal abd[24], bce[24], cda[24], deb[24], eac[24];
  int abclen, bcdlen, cdelen, dealen, eablen;
  int abdlen, bcelen, cdalen, deblen, eaclen;
  starreal temp48a[48], temp48b[48];
  int temp48alen, temp48blen;
  starreal abcd[96], bcde[96], cdea[96], deab[96], eabc[96];
  int abcdlen, bcdelen, cdealen, deablen, eabclen;
  starreal temp192[192];
  starreal det384x[384], det384y[384], det384z[384];
  int xlen, ylen, zlen;
  starreal detxy[768];
  int xylen;
  starreal adet[1152], bdet[1152], cdet[1152], ddet[1152], edet[1152];
  int alen, blen, clen, dlen, elen;
  starreal abdet[2304], cddet[2304], cdedet[3456];
  int ablen, cdlen;
  starreal deter[5760];
  int deterlen;
  int i;

  INEXACT starreal bvirt;
  starreal avirt, bround, around;
  INEXACT starreal c;
  INEXACT starreal abig;
  starreal ahi, alo, bhi, blo;
  starreal err1, err2, err3;
  INEXACT starreal _i, _j;
  starreal _0;

  Two_Product(pa[0], pb[1], axby1, axby0);
  Two_Product(pb[0], pa[1], bxay1, bxay0);
  Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]);

  Two_Product(pb[0], pc[1], bxcy1, bxcy0);
  Two_Product(pc[0], pb[1], cxby1, cxby0);
  Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]);

  Two_Product(pc[0], pd[1], cxdy1, cxdy0);
  Two_Product(pd[0], pc[1], dxcy1, dxcy0);
  Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]);

  Two_Product(pd[0], pe[1], dxey1, dxey0);
  Two_Product(pe[0], pd[1], exdy1, exdy0);
  Two_Two_Diff(dxey1, dxey0, exdy1, exdy0, de[3], de[2], de[1], de[0]);

  Two_Product(pe[0], pa[1], exay1, exay0);
  Two_Product(pa[0], pe[1], axey1, axey0);
  Two_Two_Diff(exay1, exay0, axey1, axey0, ea[3], ea[2], ea[1], ea[0]);

  Two_Product(pa[0], pc[1], axcy1, axcy0);
  Two_Product(pc[0], pa[1], cxay1, cxay0);
  Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]);

  Two_Product(pb[0], pd[1], bxdy1, bxdy0);
  Two_Product(pd[0], pb[1], dxby1, dxby0);
  Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]);

  Two_Product(pc[0], pe[1], cxey1, cxey0);
  Two_Product(pe[0], pc[1], excy1, excy0);
  Two_Two_Diff(cxey1, cxey0, excy1, excy0, ce[3], ce[2], ce[1], ce[0]);

  Two_Product(pd[0], pa[1], dxay1, dxay0);
  Two_Product(pa[0], pd[1], axdy1, axdy0);
  Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]);

  Two_Product(pe[0], pb[1], exby1, exby0);
  Two_Product(pb[0], pe[1], bxey1, bxey0);
  Two_Two_Diff(exby1, exby0, bxey1, bxey0, eb[3], eb[2], eb[1], eb[0]);

  temp8alen = scale_expansion_zeroelim(4, bc, pa[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, ac, -pb[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, ab, pc[2], temp8a);
  abclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       abc);

  temp8alen = scale_expansion_zeroelim(4, cd, pb[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, bd, -pc[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, bc, pd[2], temp8a);
  bcdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       bcd);

  temp8alen = scale_expansion_zeroelim(4, de, pc[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, ce, -pd[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, cd, pe[2], temp8a);
  cdelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       cde);

  temp8alen = scale_expansion_zeroelim(4, ea, pd[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, da, -pe[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, de, pa[2], temp8a);
  dealen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       dea);

  temp8alen = scale_expansion_zeroelim(4, ab, pe[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, eb, -pa[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, ea, pb[2], temp8a);
  eablen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       eab);

  temp8alen = scale_expansion_zeroelim(4, bd, pa[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, da, pb[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, ab, pd[2], temp8a);
  abdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       abd);

  temp8alen = scale_expansion_zeroelim(4, ce, pb[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, eb, pc[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, bc, pe[2], temp8a);
  bcelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       bce);

  temp8alen = scale_expansion_zeroelim(4, da, pc[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, ac, pd[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, cd, pa[2], temp8a);
  cdalen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       cda);

  temp8alen = scale_expansion_zeroelim(4, eb, pd[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, bd, pe[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, de, pb[2], temp8a);
  deblen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       deb);

  temp8alen = scale_expansion_zeroelim(4, ac, pe[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, ce, pa[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, ea, pc[2], temp8a);
  eaclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       eac);

  temp48alen = fast_expansion_sum_zeroelim(cdelen, cde, bcelen, bce, temp48a);
  temp48blen = fast_expansion_sum_zeroelim(deblen, deb, bcdlen, bcd, temp48b);
  for (i = 0; i < temp48blen; i++) {
    temp48b[i] = -temp48b[i];
  }
  bcdelen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
                                        temp48blen, temp48b, bcde);
  xlen = scale_expansion_zeroelim(bcdelen, bcde, pa[0], temp192);
  xlen = scale_expansion_zeroelim(xlen, temp192, pa[0], det384x);
  ylen = scale_expansion_zeroelim(bcdelen, bcde, pa[1], temp192);
  ylen = scale_expansion_zeroelim(ylen, temp192, pa[1], det384y);
  zlen = scale_expansion_zeroelim(bcdelen, bcde, pa[2], temp192);
  zlen = scale_expansion_zeroelim(zlen, temp192, pa[2], det384z);
  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
  alen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, adet);

  temp48alen = fast_expansion_sum_zeroelim(dealen, dea, cdalen, cda, temp48a);
  temp48blen = fast_expansion_sum_zeroelim(eaclen, eac, cdelen, cde, temp48b);
  for (i = 0; i < temp48blen; i++) {
    temp48b[i] = -temp48b[i];
  }
  cdealen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
                                        temp48blen, temp48b, cdea);
  xlen = scale_expansion_zeroelim(cdealen, cdea, pb[0], temp192);
  xlen = scale_expansion_zeroelim(xlen, temp192, pb[0], det384x);
  ylen = scale_expansion_zeroelim(cdealen, cdea, pb[1], temp192);
  ylen = scale_expansion_zeroelim(ylen, temp192, pb[1], det384y);
  zlen = scale_expansion_zeroelim(cdealen, cdea, pb[2], temp192);
  zlen = scale_expansion_zeroelim(zlen, temp192, pb[2], det384z);
  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
  blen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, bdet);

  temp48alen = fast_expansion_sum_zeroelim(eablen, eab, deblen, deb, temp48a);
  temp48blen = fast_expansion_sum_zeroelim(abdlen, abd, dealen, dea, temp48b);
  for (i = 0; i < temp48blen; i++) {
    temp48b[i] = -temp48b[i];
  }
  deablen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
                                        temp48blen, temp48b, deab);
  xlen = scale_expansion_zeroelim(deablen, deab, pc[0], temp192);
  xlen = scale_expansion_zeroelim(xlen, temp192, pc[0], det384x);
  ylen = scale_expansion_zeroelim(deablen, deab, pc[1], temp192);
  ylen = scale_expansion_zeroelim(ylen, temp192, pc[1], det384y);
  zlen = scale_expansion_zeroelim(deablen, deab, pc[2], temp192);
  zlen = scale_expansion_zeroelim(zlen, temp192, pc[2], det384z);
  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
  clen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, cdet);

  temp48alen = fast_expansion_sum_zeroelim(abclen, abc, eaclen, eac, temp48a);
  temp48blen = fast_expansion_sum_zeroelim(bcelen, bce, eablen, eab, temp48b);
  for (i = 0; i < temp48blen; i++) {
    temp48b[i] = -temp48b[i];
  }
  eabclen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
                                        temp48blen, temp48b, eabc);
  xlen = scale_expansion_zeroelim(eabclen, eabc, pd[0], temp192);
  xlen = scale_expansion_zeroelim(xlen, temp192, pd[0], det384x);
  ylen = scale_expansion_zeroelim(eabclen, eabc, pd[1], temp192);
  ylen = scale_expansion_zeroelim(ylen, temp192, pd[1], det384y);
  zlen = scale_expansion_zeroelim(eabclen, eabc, pd[2], temp192);
  zlen = scale_expansion_zeroelim(zlen, temp192, pd[2], det384z);
  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
  dlen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, ddet);

  temp48alen = fast_expansion_sum_zeroelim(bcdlen, bcd, abdlen, abd, temp48a);
  temp48blen = fast_expansion_sum_zeroelim(cdalen, cda, abclen, abc, temp48b);
  for (i = 0; i < temp48blen; i++) {
    temp48b[i] = -temp48b[i];
  }
  abcdlen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
                                        temp48blen, temp48b, abcd);
  xlen = scale_expansion_zeroelim(abcdlen, abcd, pe[0], temp192);
  xlen = scale_expansion_zeroelim(xlen, temp192, pe[0], det384x);
  ylen = scale_expansion_zeroelim(abcdlen, abcd, pe[1], temp192);
  ylen = scale_expansion_zeroelim(ylen, temp192, pe[1], det384y);
  zlen = scale_expansion_zeroelim(abcdlen, abcd, pe[2], temp192);
  zlen = scale_expansion_zeroelim(zlen, temp192, pe[2], det384z);
  xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy);
  elen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, edet);

  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
  cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet);
  cdelen = fast_expansion_sum_zeroelim(cdlen, cddet, elen, edet, cdedet);
  deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdelen, cdedet, deter);

  return deter[deterlen - 1];
}

starreal insphereadapt(starreal *pa,
                       starreal *pb,
                       starreal *pc,
                       starreal *pd,
                       starreal *pe,
                       starreal permanent)
{
  INEXACT starreal aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez;
  starreal det, errbound;

  INEXACT starreal aexbey1, bexaey1, bexcey1, cexbey1;
  INEXACT starreal cexdey1, dexcey1, dexaey1, aexdey1;
  INEXACT starreal aexcey1, cexaey1, bexdey1, dexbey1;
  starreal aexbey0, bexaey0, bexcey0, cexbey0;
  starreal cexdey0, dexcey0, dexaey0, aexdey0;
  starreal aexcey0, cexaey0, bexdey0, dexbey0;
  starreal ab[4], bc[4], cd[4], da[4], ac[4], bd[4];
  INEXACT starreal ab3, bc3, cd3, da3, ac3, bd3;
  starreal abeps, bceps, cdeps, daeps, aceps, bdeps;
  starreal temp8a[8], temp8b[8], temp8c[8], temp16[16], temp24[24], temp48[48];
  int temp8alen, temp8blen, temp8clen, temp16len, temp24len, temp48len;
  starreal xdet[96], ydet[96], zdet[96], xydet[192];
  int xlen, ylen, zlen, xylen;
  starreal adet[288], bdet[288], cdet[288], ddet[288];
  int alen, blen, clen, dlen;
  starreal abdet[576], cddet[576];
  int ablen, cdlen;
  starreal fin1[1152];
  int finlength;

  starreal aextail, bextail, cextail, dextail;
  starreal aeytail, beytail, ceytail, deytail;
  starreal aeztail, beztail, ceztail, deztail;

  INEXACT starreal bvirt;
  starreal avirt, bround, around;
  INEXACT starreal c;
  INEXACT starreal abig;
  starreal ahi, alo, bhi, blo;
  starreal err1, err2, err3;
  INEXACT starreal _i, _j;
  starreal _0;

  aex = (starreal) (pa[0] - pe[0]);
  bex = (starreal) (pb[0] - pe[0]);
  cex = (starreal) (pc[0] - pe[0]);
  dex = (starreal) (pd[0] - pe[0]);
  aey = (starreal) (pa[1] - pe[1]);
  bey = (starreal) (pb[1] - pe[1]);
  cey = (starreal) (pc[1] - pe[1]);
  dey = (starreal) (pd[1] - pe[1]);
  aez = (starreal) (pa[2] - pe[2]);
  bez = (starreal) (pb[2] - pe[2]);
  cez = (starreal) (pc[2] - pe[2]);
  dez = (starreal) (pd[2] - pe[2]);

  Two_Product(aex, bey, aexbey1, aexbey0);
  Two_Product(bex, aey, bexaey1, bexaey0);
  Two_Two_Diff(aexbey1, aexbey0, bexaey1, bexaey0, ab3, ab[2], ab[1], ab[0]);
  ab[3] = ab3;

  Two_Product(bex, cey, bexcey1, bexcey0);
  Two_Product(cex, bey, cexbey1, cexbey0);
  Two_Two_Diff(bexcey1, bexcey0, cexbey1, cexbey0, bc3, bc[2], bc[1], bc[0]);
  bc[3] = bc3;

  Two_Product(cex, dey, cexdey1, cexdey0);
  Two_Product(dex, cey, dexcey1, dexcey0);
  Two_Two_Diff(cexdey1, cexdey0, dexcey1, dexcey0, cd3, cd[2], cd[1], cd[0]);
  cd[3] = cd3;

  Two_Product(dex, aey, dexaey1, dexaey0);
  Two_Product(aex, dey, aexdey1, aexdey0);
  Two_Two_Diff(dexaey1, dexaey0, aexdey1, aexdey0, da3, da[2], da[1], da[0]);
  da[3] = da3;

  Two_Product(aex, cey, aexcey1, aexcey0);
  Two_Product(cex, aey, cexaey1, cexaey0);
  Two_Two_Diff(aexcey1, aexcey0, cexaey1, cexaey0, ac3, ac[2], ac[1], ac[0]);
  ac[3] = ac3;

  Two_Product(bex, dey, bexdey1, bexdey0);
  Two_Product(dex, bey, dexbey1, dexbey0);
  Two_Two_Diff(bexdey1, bexdey0, dexbey1, dexbey0, bd3, bd[2], bd[1], bd[0]);
  bd[3] = bd3;

  temp8alen = scale_expansion_zeroelim(4, cd, bez, temp8a);
  temp8blen = scale_expansion_zeroelim(4, bd, -cez, temp8b);
  temp8clen = scale_expansion_zeroelim(4, bc, dez, temp8c);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
                                          temp8blen, temp8b, temp16);
  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
                                          temp16len, temp16, temp24);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, aex, temp48);
  xlen = scale_expansion_zeroelim(temp48len, temp48, -aex, xdet);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, aey, temp48);
  ylen = scale_expansion_zeroelim(temp48len, temp48, -aey, ydet);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, aez, temp48);
  zlen = scale_expansion_zeroelim(temp48len, temp48, -aez, zdet);
  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
  alen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, adet);

  temp8alen = scale_expansion_zeroelim(4, da, cez, temp8a);
  temp8blen = scale_expansion_zeroelim(4, ac, dez, temp8b);
  temp8clen = scale_expansion_zeroelim(4, cd, aez, temp8c);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
                                          temp8blen, temp8b, temp16);
  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
                                          temp16len, temp16, temp24);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, bex, temp48);
  xlen = scale_expansion_zeroelim(temp48len, temp48, bex, xdet);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, bey, temp48);
  ylen = scale_expansion_zeroelim(temp48len, temp48, bey, ydet);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, bez, temp48);
  zlen = scale_expansion_zeroelim(temp48len, temp48, bez, zdet);
  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
  blen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, bdet);

  temp8alen = scale_expansion_zeroelim(4, ab, dez, temp8a);
  temp8blen = scale_expansion_zeroelim(4, bd, aez, temp8b);
  temp8clen = scale_expansion_zeroelim(4, da, bez, temp8c);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
                                          temp8blen, temp8b, temp16);
  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
                                          temp16len, temp16, temp24);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, cex, temp48);
  xlen = scale_expansion_zeroelim(temp48len, temp48, -cex, xdet);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, cey, temp48);
  ylen = scale_expansion_zeroelim(temp48len, temp48, -cey, ydet);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, cez, temp48);
  zlen = scale_expansion_zeroelim(temp48len, temp48, -cez, zdet);
  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
  clen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, cdet);

  temp8alen = scale_expansion_zeroelim(4, bc, aez, temp8a);
  temp8blen = scale_expansion_zeroelim(4, ac, -bez, temp8b);
  temp8clen = scale_expansion_zeroelim(4, ab, cez, temp8c);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
                                          temp8blen, temp8b, temp16);
  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
                                          temp16len, temp16, temp24);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, dex, temp48);
  xlen = scale_expansion_zeroelim(temp48len, temp48, dex, xdet);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, dey, temp48);
  ylen = scale_expansion_zeroelim(temp48len, temp48, dey, ydet);
  temp48len = scale_expansion_zeroelim(temp24len, temp24, dez, temp48);
  zlen = scale_expansion_zeroelim(temp48len, temp48, dez, zdet);
  xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet);
  dlen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, ddet);

  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
  cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet);
  finlength = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, fin1);

  det = estimate(finlength, fin1);
  errbound = isperrboundB * permanent;
  if ((det >= errbound) || (-det >= errbound)) {
    return det;
  }

  Two_Diff_Tail(pa[0], pe[0], aex, aextail);
  Two_Diff_Tail(pa[1], pe[1], aey, aeytail);
  Two_Diff_Tail(pa[2], pe[2], aez, aeztail);
  Two_Diff_Tail(pb[0], pe[0], bex, bextail);
  Two_Diff_Tail(pb[1], pe[1], bey, beytail);
  Two_Diff_Tail(pb[2], pe[2], bez, beztail);
  Two_Diff_Tail(pc[0], pe[0], cex, cextail);
  Two_Diff_Tail(pc[1], pe[1], cey, ceytail);
  Two_Diff_Tail(pc[2], pe[2], cez, ceztail);
  Two_Diff_Tail(pd[0], pe[0], dex, dextail);
  Two_Diff_Tail(pd[1], pe[1], dey, deytail);
  Two_Diff_Tail(pd[2], pe[2], dez, deztail);
  if ((aextail == 0.0) && (aeytail == 0.0) && (aeztail == 0.0) &&
      (bextail == 0.0) && (beytail == 0.0) && (beztail == 0.0) &&
      (cextail == 0.0) && (ceytail == 0.0) && (ceztail == 0.0) &&
      (dextail == 0.0) && (deytail == 0.0) && (deztail == 0.0)) {
    return det;
  }

  errbound = isperrboundC * permanent + resulterrbound * Absolute(det);
  abeps = (aex * beytail + bey * aextail)
        - (aey * bextail + bex * aeytail);
  bceps = (bex * ceytail + cey * bextail)
        - (bey * cextail + cex * beytail);
  cdeps = (cex * deytail + dey * cextail)
        - (cey * dextail + dex * ceytail);
  daeps = (dex * aeytail + aey * dextail)
        - (dey * aextail + aex * deytail);
  aceps = (aex * ceytail + cey * aextail)
        - (aey * cextail + cex * aeytail);
  bdeps = (bex * deytail + dey * bextail)
        - (bey * dextail + dex * beytail);
  det += (((bex * bex + bey * bey + bez * bez)
           * ((cez * daeps + dez * aceps + aez * cdeps)
              + (ceztail * da3 + deztail * ac3 + aeztail * cd3))
           + (dex * dex + dey * dey + dez * dez)
           * ((aez * bceps - bez * aceps + cez * abeps)
              + (aeztail * bc3 - beztail * ac3 + ceztail * ab3)))
          - ((aex * aex + aey * aey + aez * aez)
           * ((bez * cdeps - cez * bdeps + dez * bceps)
              + (beztail * cd3 - ceztail * bd3 + deztail * bc3))
           + (cex * cex + cey * cey + cez * cez)
           * ((dez * abeps + aez * bdeps + bez * daeps)
              + (deztail * ab3 + aeztail * bd3 + beztail * da3))))
       + 2.0 * (((bex * bextail + bey * beytail + bez * beztail)
                 * (cez * da3 + dez * ac3 + aez * cd3)
                 + (dex * dextail + dey * deytail + dez * deztail)
                 * (aez * bc3 - bez * ac3 + cez * ab3))
                - ((aex * aextail + aey * aeytail + aez * aeztail)
                 * (bez * cd3 - cez * bd3 + dez * bc3)
                 + (cex * cextail + cey * ceytail + cez * ceztail)
                 * (dez * ab3 + aez * bd3 + bez * da3)));
  if ((det >= errbound) || (-det >= errbound)) {
    return det;
  }

  return insphereexact(pa, pb, pc, pd, pe);
}

starreal insphere(struct behavior *b,
                  starreal *pa,
                  starreal *pb,
                  starreal *pc,
                  starreal *pd,
                  starreal *pe)
{
  starreal aex, bex, cex, dex;
  starreal aey, bey, cey, dey;
  starreal aez, bez, cez, dez;
  starreal aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey;
  starreal aexcey, cexaey, bexdey, dexbey;
  starreal alift, blift, clift, dlift;
  starreal ab, bc, cd, da, ac, bd;
  starreal abc, bcd, cda, dab;
  starreal aezplus, bezplus, cezplus, dezplus;
  starreal aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus;
  starreal cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus;
  starreal aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus;
  starreal det;
  starreal permanent, errbound;

  b->inspherecount++;

  aex = pa[0] - pe[0];
  bex = pb[0] - pe[0];
  cex = pc[0] - pe[0];
  dex = pd[0] - pe[0];
  aey = pa[1] - pe[1];
  bey = pb[1] - pe[1];
  cey = pc[1] - pe[1];
  dey = pd[1] - pe[1];
  aez = pa[2] - pe[2];
  bez = pb[2] - pe[2];
  cez = pc[2] - pe[2];
  dez = pd[2] - pe[2];

  aexbey = aex * bey;
  bexaey = bex * aey;
  ab = aexbey - bexaey;
  bexcey = bex * cey;
  cexbey = cex * bey;
  bc = bexcey - cexbey;
  cexdey = cex * dey;
  dexcey = dex * cey;
  cd = cexdey - dexcey;
  dexaey = dex * aey;
  aexdey = aex * dey;
  da = dexaey - aexdey;

  aexcey = aex * cey;
  cexaey = cex * aey;
  ac = aexcey - cexaey;
  bexdey = bex * dey;
  dexbey = dex * bey;
  bd = bexdey - dexbey;

  abc = aez * bc - bez * ac + cez * ab;
  bcd = bez * cd - cez * bd + dez * bc;
  cda = cez * da + dez * ac + aez * cd;
  dab = dez * ab + aez * bd + bez * da;

  alift = aex * aex + aey * aey + aez * aez;
  blift = bex * bex + bey * bey + bez * bez;
  clift = cex * cex + cey * cey + cez * cez;
  dlift = dex * dex + dey * dey + dez * dez;

  det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd);

  if (b->noexact) {
    return det;
  }

  aezplus = Absolute(aez);
  bezplus = Absolute(bez);
  cezplus = Absolute(cez);
  dezplus = Absolute(dez);
  aexbeyplus = Absolute(aexbey);
  bexaeyplus = Absolute(bexaey);
  bexceyplus = Absolute(bexcey);
  cexbeyplus = Absolute(cexbey);
  cexdeyplus = Absolute(cexdey);
  dexceyplus = Absolute(dexcey);
  dexaeyplus = Absolute(dexaey);
  aexdeyplus = Absolute(aexdey);
  aexceyplus = Absolute(aexcey);
  cexaeyplus = Absolute(cexaey);
  bexdeyplus = Absolute(bexdey);
  dexbeyplus = Absolute(dexbey);
  permanent = ((cexdeyplus + dexceyplus) * bezplus
               + (dexbeyplus + bexdeyplus) * cezplus
               + (bexceyplus + cexbeyplus) * dezplus)
            * alift
            + ((dexaeyplus + aexdeyplus) * cezplus
               + (aexceyplus + cexaeyplus) * dezplus
               + (cexdeyplus + dexceyplus) * aezplus)
            * blift
            + ((aexbeyplus + bexaeyplus) * dezplus
               + (bexdeyplus + dexbeyplus) * aezplus
               + (dexaeyplus + aexdeyplus) * bezplus)
            * clift
            + ((bexceyplus + cexbeyplus) * aezplus
               + (cexaeyplus + aexceyplus) * bezplus
               + (aexbeyplus + bexaeyplus) * cezplus)
            * dlift;
  errbound = isperrboundA * permanent;
  if ((det > errbound) || (-det > errbound)) {
    return det;
  }

  return insphereadapt(pa, pb, pc, pd, pe, permanent);
}

/*****************************************************************************/
/*                                                                           */
/*  orient4d()   Return a positive value if the point pe lies above the      */
/*               hyperplane passing through pa, pb, pc, and pd; "above" is   */
/*               defined in a manner best found by trial-and-error.  Returns */
/*               a negative value if pe lies below the hyperplane.  Returns  */
/*               zero if the points are co-hyperplanar (not affinely         */
/*               independent).  The result is also a rough approximation of  */
/*               24 times the signed volume of the 4-simplex defined by the  */
/*               five points.                                                */
/*                                                                           */
/*  Uses exact arithmetic if necessary to ensure a correct answer.  The      */
/*  result returned is the determinant of a matrix.  This determinant is     */
/*  computed adaptively, in the sense that exact arithmetic is used only to  */
/*  the degree it is needed to ensure that the returned value has the        */
/*  correct sign.  Hence, orient4d() is usually quite fast, but will run     */
/*  more slowly when the input points are hyper-coplanar or nearly so.       */
/*                                                                           */
/*  See my Robust Predicates paper for details.                              */
/*                                                                           */
/*****************************************************************************/

starreal orient4dexact(starreal *pa,
                       starreal *pb,
                       starreal *pc,
                       starreal *pd,
                       starreal *pe,
                       starreal aheight,
                       starreal bheight,
                       starreal cheight,
                       starreal dheight,
                       starreal eheight)
{
  INEXACT starreal axby1, bxcy1, cxdy1, dxey1, exay1;
  INEXACT starreal bxay1, cxby1, dxcy1, exdy1, axey1;
  INEXACT starreal axcy1, bxdy1, cxey1, dxay1, exby1;
  INEXACT starreal cxay1, dxby1, excy1, axdy1, bxey1;
  starreal axby0, bxcy0, cxdy0, dxey0, exay0;
  starreal bxay0, cxby0, dxcy0, exdy0, axey0;
  starreal axcy0, bxdy0, cxey0, dxay0, exby0;
  starreal cxay0, dxby0, excy0, axdy0, bxey0;
  starreal ab[4], bc[4], cd[4], de[4], ea[4];
  starreal ac[4], bd[4], ce[4], da[4], eb[4];
  starreal temp8a[8], temp8b[8], temp16[16];
  int temp8alen, temp8blen, temp16len;
  starreal abc[24], bcd[24], cde[24], dea[24], eab[24];
  starreal abd[24], bce[24], cda[24], deb[24], eac[24];
  int abclen, bcdlen, cdelen, dealen, eablen;
  int abdlen, bcelen, cdalen, deblen, eaclen;
  starreal temp48a[48], temp48b[48];
  int temp48alen, temp48blen;
  starreal abcd[96], bcde[96], cdea[96], deab[96], eabc[96];
  int abcdlen, bcdelen, cdealen, deablen, eabclen;
  starreal adet[192], bdet[192], cdet[192], ddet[192], edet[192];
  int alen, blen, clen, dlen, elen;
  starreal abdet[384], cddet[384], cdedet[576];
  int ablen, cdlen;
  starreal deter[960];
  int deterlen;
  int i;

  INEXACT starreal bvirt;
  starreal avirt, bround, around;
  INEXACT starreal c;
  INEXACT starreal abig;
  starreal ahi, alo, bhi, blo;
  starreal err1, err2, err3;
  INEXACT starreal _i, _j;
  starreal _0;

  Two_Product(pa[0], pb[1], axby1, axby0);
  Two_Product(pb[0], pa[1], bxay1, bxay0);
  Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]);

  Two_Product(pb[0], pc[1], bxcy1, bxcy0);
  Two_Product(pc[0], pb[1], cxby1, cxby0);
  Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]);

  Two_Product(pc[0], pd[1], cxdy1, cxdy0);
  Two_Product(pd[0], pc[1], dxcy1, dxcy0);
  Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]);

  Two_Product(pd[0], pe[1], dxey1, dxey0);
  Two_Product(pe[0], pd[1], exdy1, exdy0);
  Two_Two_Diff(dxey1, dxey0, exdy1, exdy0, de[3], de[2], de[1], de[0]);

  Two_Product(pe[0], pa[1], exay1, exay0);
  Two_Product(pa[0], pe[1], axey1, axey0);
  Two_Two_Diff(exay1, exay0, axey1, axey0, ea[3], ea[2], ea[1], ea[0]);

  Two_Product(pa[0], pc[1], axcy1, axcy0);
  Two_Product(pc[0], pa[1], cxay1, cxay0);
  Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]);

  Two_Product(pb[0], pd[1], bxdy1, bxdy0);
  Two_Product(pd[0], pb[1], dxby1, dxby0);
  Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]);

  Two_Product(pc[0], pe[1], cxey1, cxey0);
  Two_Product(pe[0], pc[1], excy1, excy0);
  Two_Two_Diff(cxey1, cxey0, excy1, excy0, ce[3], ce[2], ce[1], ce[0]);

  Two_Product(pd[0], pa[1], dxay1, dxay0);
  Two_Product(pa[0], pd[1], axdy1, axdy0);
  Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]);

  Two_Product(pe[0], pb[1], exby1, exby0);
  Two_Product(pb[0], pe[1], bxey1, bxey0);
  Two_Two_Diff(exby1, exby0, bxey1, bxey0, eb[3], eb[2], eb[1], eb[0]);

  temp8alen = scale_expansion_zeroelim(4, bc, pa[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, ac, -pb[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, ab, pc[2], temp8a);
  abclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       abc);

  temp8alen = scale_expansion_zeroelim(4, cd, pb[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, bd, -pc[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, bc, pd[2], temp8a);
  bcdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       bcd);

  temp8alen = scale_expansion_zeroelim(4, de, pc[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, ce, -pd[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, cd, pe[2], temp8a);
  cdelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       cde);

  temp8alen = scale_expansion_zeroelim(4, ea, pd[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, da, -pe[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, de, pa[2], temp8a);
  dealen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       dea);

  temp8alen = scale_expansion_zeroelim(4, ab, pe[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, eb, -pa[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, ea, pb[2], temp8a);
  eablen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       eab);

  temp8alen = scale_expansion_zeroelim(4, bd, pa[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, da, pb[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, ab, pd[2], temp8a);
  abdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       abd);

  temp8alen = scale_expansion_zeroelim(4, ce, pb[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, eb, pc[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, bc, pe[2], temp8a);
  bcelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       bce);

  temp8alen = scale_expansion_zeroelim(4, da, pc[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, ac, pd[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, cd, pa[2], temp8a);
  cdalen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       cda);

  temp8alen = scale_expansion_zeroelim(4, eb, pd[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, bd, pe[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, de, pb[2], temp8a);
  deblen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       deb);

  temp8alen = scale_expansion_zeroelim(4, ac, pe[2], temp8a);
  temp8blen = scale_expansion_zeroelim(4, ce, pa[2], temp8b);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b,
                                          temp16);
  temp8alen = scale_expansion_zeroelim(4, ea, pc[2], temp8a);
  eaclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16,
                                       eac);

  temp48alen = fast_expansion_sum_zeroelim(cdelen, cde, bcelen, bce, temp48a);
  temp48blen = fast_expansion_sum_zeroelim(deblen, deb, bcdlen, bcd, temp48b);
  for (i = 0; i < temp48blen; i++) {
    temp48b[i] = -temp48b[i];
  }
  bcdelen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
                                        temp48blen, temp48b, bcde);
  alen = scale_expansion_zeroelim(bcdelen, bcde, aheight, adet);

  temp48alen = fast_expansion_sum_zeroelim(dealen, dea, cdalen, cda, temp48a);
  temp48blen = fast_expansion_sum_zeroelim(eaclen, eac, cdelen, cde, temp48b);
  for (i = 0; i < temp48blen; i++) {
    temp48b[i] = -temp48b[i];
  }
  cdealen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
                                        temp48blen, temp48b, cdea);
  blen = scale_expansion_zeroelim(cdealen, cdea, bheight, bdet);

  temp48alen = fast_expansion_sum_zeroelim(eablen, eab, deblen, deb, temp48a);
  temp48blen = fast_expansion_sum_zeroelim(abdlen, abd, dealen, dea, temp48b);
  for (i = 0; i < temp48blen; i++) {
    temp48b[i] = -temp48b[i];
  }
  deablen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
                                        temp48blen, temp48b, deab);
  clen = scale_expansion_zeroelim(deablen, deab, cheight, cdet);

  temp48alen = fast_expansion_sum_zeroelim(abclen, abc, eaclen, eac, temp48a);
  temp48blen = fast_expansion_sum_zeroelim(bcelen, bce, eablen, eab, temp48b);
  for (i = 0; i < temp48blen; i++) {
    temp48b[i] = -temp48b[i];
  }
  eabclen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
                                        temp48blen, temp48b, eabc);
  dlen = scale_expansion_zeroelim(eabclen, eabc, dheight, ddet);

  temp48alen = fast_expansion_sum_zeroelim(bcdlen, bcd, abdlen, abd, temp48a);
  temp48blen = fast_expansion_sum_zeroelim(cdalen, cda, abclen, abc, temp48b);
  for (i = 0; i < temp48blen; i++) {
    temp48b[i] = -temp48b[i];
  }
  abcdlen = fast_expansion_sum_zeroelim(temp48alen, temp48a,
                                        temp48blen, temp48b, abcd);
  elen = scale_expansion_zeroelim(abcdlen, abcd, eheight, edet);

  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
  cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet);
  cdelen = fast_expansion_sum_zeroelim(cdlen, cddet, elen, edet, cdedet);
  deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdelen, cdedet, deter);

  return deter[deterlen - 1];
}

starreal orient4dadapt(starreal *pa,
                       starreal *pb,
                       starreal *pc,
                       starreal *pd,
                       starreal *pe,
                       starreal aheight,
                       starreal bheight,
                       starreal cheight,
                       starreal dheight,
                       starreal eheight,
                       starreal permanent)
{
  INEXACT starreal aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez;
  INEXACT starreal aeheight, beheight, ceheight, deheight;
  starreal det, errbound;

  INEXACT starreal aexbey1, bexaey1, bexcey1, cexbey1;
  INEXACT starreal cexdey1, dexcey1, dexaey1, aexdey1;
  INEXACT starreal aexcey1, cexaey1, bexdey1, dexbey1;
  starreal aexbey0, bexaey0, bexcey0, cexbey0;
  starreal cexdey0, dexcey0, dexaey0, aexdey0;
  starreal aexcey0, cexaey0, bexdey0, dexbey0;
  starreal ab[4], bc[4], cd[4], da[4], ac[4], bd[4];
  INEXACT starreal ab3, bc3, cd3, da3, ac3, bd3;
  starreal abeps, bceps, cdeps, daeps, aceps, bdeps;
  starreal temp8a[8], temp8b[8], temp8c[8], temp16[16], temp24[24];
  int temp8alen, temp8blen, temp8clen, temp16len, temp24len;
  starreal adet[48], bdet[48], cdet[48], ddet[48];
  int alen, blen, clen, dlen;
  starreal abdet[96], cddet[96];
  int ablen, cdlen;
  starreal fin1[192];
  int finlength;

  starreal aextail, bextail, cextail, dextail;
  starreal aeytail, beytail, ceytail, deytail;
  starreal aeztail, beztail, ceztail, deztail;
  starreal aeheighttail, beheighttail, ceheighttail, deheighttail;

  INEXACT starreal bvirt;
  starreal avirt, bround, around;
  INEXACT starreal c;
  INEXACT starreal abig;
  starreal ahi, alo, bhi, blo;
  starreal err1, err2, err3;
  INEXACT starreal _i, _j;
  starreal _0;

  aex = (starreal) (pa[0] - pe[0]);
  bex = (starreal) (pb[0] - pe[0]);
  cex = (starreal) (pc[0] - pe[0]);
  dex = (starreal) (pd[0] - pe[0]);
  aey = (starreal) (pa[1] - pe[1]);
  bey = (starreal) (pb[1] - pe[1]);
  cey = (starreal) (pc[1] - pe[1]);
  dey = (starreal) (pd[1] - pe[1]);
  aez = (starreal) (pa[2] - pe[2]);
  bez = (starreal) (pb[2] - pe[2]);
  cez = (starreal) (pc[2] - pe[2]);
  dez = (starreal) (pd[2] - pe[2]);
  aeheight = (starreal) (aheight - eheight);
  beheight = (starreal) (bheight - eheight);
  ceheight = (starreal) (cheight - eheight);
  deheight = (starreal) (dheight - eheight);

  Two_Product(aex, bey, aexbey1, aexbey0);
  Two_Product(bex, aey, bexaey1, bexaey0);
  Two_Two_Diff(aexbey1, aexbey0, bexaey1, bexaey0, ab3, ab[2], ab[1], ab[0]);
  ab[3] = ab3;

  Two_Product(bex, cey, bexcey1, bexcey0);
  Two_Product(cex, bey, cexbey1, cexbey0);
  Two_Two_Diff(bexcey1, bexcey0, cexbey1, cexbey0, bc3, bc[2], bc[1], bc[0]);
  bc[3] = bc3;

  Two_Product(cex, dey, cexdey1, cexdey0);
  Two_Product(dex, cey, dexcey1, dexcey0);
  Two_Two_Diff(cexdey1, cexdey0, dexcey1, dexcey0, cd3, cd[2], cd[1], cd[0]);
  cd[3] = cd3;

  Two_Product(dex, aey, dexaey1, dexaey0);
  Two_Product(aex, dey, aexdey1, aexdey0);
  Two_Two_Diff(dexaey1, dexaey0, aexdey1, aexdey0, da3, da[2], da[1], da[0]);
  da[3] = da3;

  Two_Product(aex, cey, aexcey1, aexcey0);
  Two_Product(cex, aey, cexaey1, cexaey0);
  Two_Two_Diff(aexcey1, aexcey0, cexaey1, cexaey0, ac3, ac[2], ac[1], ac[0]);
  ac[3] = ac3;

  Two_Product(bex, dey, bexdey1, bexdey0);
  Two_Product(dex, bey, dexbey1, dexbey0);
  Two_Two_Diff(bexdey1, bexdey0, dexbey1, dexbey0, bd3, bd[2], bd[1], bd[0]);
  bd[3] = bd3;

  temp8alen = scale_expansion_zeroelim(4, cd, bez, temp8a);
  temp8blen = scale_expansion_zeroelim(4, bd, -cez, temp8b);
  temp8clen = scale_expansion_zeroelim(4, bc, dez, temp8c);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
                                          temp8blen, temp8b, temp16);
  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
                                          temp16len, temp16, temp24);
  alen = scale_expansion_zeroelim(temp24len, temp24, -aeheight, adet);

  temp8alen = scale_expansion_zeroelim(4, da, cez, temp8a);
  temp8blen = scale_expansion_zeroelim(4, ac, dez, temp8b);
  temp8clen = scale_expansion_zeroelim(4, cd, aez, temp8c);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
                                          temp8blen, temp8b, temp16);
  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
                                          temp16len, temp16, temp24);
  blen = scale_expansion_zeroelim(temp24len, temp24, beheight, bdet);

  temp8alen = scale_expansion_zeroelim(4, ab, dez, temp8a);
  temp8blen = scale_expansion_zeroelim(4, bd, aez, temp8b);
  temp8clen = scale_expansion_zeroelim(4, da, bez, temp8c);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
                                          temp8blen, temp8b, temp16);
  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
                                          temp16len, temp16, temp24);
  clen = scale_expansion_zeroelim(temp24len, temp24, -ceheight, cdet);

  temp8alen = scale_expansion_zeroelim(4, bc, aez, temp8a);
  temp8blen = scale_expansion_zeroelim(4, ac, -bez, temp8b);
  temp8clen = scale_expansion_zeroelim(4, ab, cez, temp8c);
  temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a,
                                          temp8blen, temp8b, temp16);
  temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c,
                                          temp16len, temp16, temp24);
  dlen = scale_expansion_zeroelim(temp24len, temp24, deheight, ddet);

  ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
  cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet);
  finlength = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, fin1);

  det = estimate(finlength, fin1);
  errbound = isperrboundB * permanent;
  if ((det >= errbound) || (-det >= errbound)) {
    return det;
  }

  Two_Diff_Tail(pa[0], pe[0], aex, aextail);
  Two_Diff_Tail(pa[1], pe[1], aey, aeytail);
  Two_Diff_Tail(pa[2], pe[2], aez, aeztail);
  Two_Diff_Tail(aheight, eheight, aeheight, aeheighttail);
  Two_Diff_Tail(pb[0], pe[0], bex, bextail);
  Two_Diff_Tail(pb[1], pe[1], bey, beytail);
  Two_Diff_Tail(pb[2], pe[2], bez, beztail);
  Two_Diff_Tail(bheight, eheight, beheight, beheighttail);
  Two_Diff_Tail(pc[0], pe[0], cex, cextail);
  Two_Diff_Tail(pc[1], pe[1], cey, ceytail);
  Two_Diff_Tail(pc[2], pe[2], cez, ceztail);
  Two_Diff_Tail(cheight, eheight, ceheight, ceheighttail);
  Two_Diff_Tail(pd[0], pe[0], dex, dextail);
  Two_Diff_Tail(pd[1], pe[1], dey, deytail);
  Two_Diff_Tail(pd[2], pe[2], dez, deztail);
  Two_Diff_Tail(dheight, eheight, deheight, deheighttail);
  if ((aextail == 0.0) && (aeytail == 0.0) && (aeztail == 0.0)
      && (bextail == 0.0) && (beytail == 0.0) && (beztail == 0.0)
      && (cextail == 0.0) && (ceytail == 0.0) && (ceztail == 0.0)
      && (dextail == 0.0) && (deytail == 0.0) && (deztail == 0.0)
      && (aeheighttail == 0.0) && (beheighttail == 0.0)
      && (ceheighttail == 0.0) && (deheighttail == 0.0)) {
    return det;
  }

  errbound = isperrboundC * permanent + resulterrbound * Absolute(det);
  abeps = (aex * beytail + bey * aextail)
        - (aey * bextail + bex * aeytail);
  bceps = (bex * ceytail + cey * bextail)
        - (bey * cextail + cex * beytail);
  cdeps = (cex * deytail + dey * cextail)
        - (cey * dextail + dex * ceytail);
  daeps = (dex * aeytail + aey * dextail)
        - (dey * aextail + aex * deytail);
  aceps = (aex * ceytail + cey * aextail)
        - (aey * cextail + cex * aeytail);
  bdeps = (bex * deytail + dey * bextail)
        - (bey * dextail + dex * beytail);
  det += ((beheight
           * ((cez * daeps + dez * aceps + aez * cdeps)
              + (ceztail * da3 + deztail * ac3 + aeztail * cd3))
           + deheight
           * ((aez * bceps - bez * aceps + cez * abeps)
              + (aeztail * bc3 - beztail * ac3 + ceztail * ab3)))
          - (aeheight
           * ((bez * cdeps - cez * bdeps + dez * bceps)
              + (beztail * cd3 - ceztail * bd3 + deztail * bc3))
           + ceheight
           * ((dez * abeps + aez * bdeps + bez * daeps)
              + (deztail * ab3 + aeztail * bd3 + beztail * da3))))
       + ((beheighttail * (cez * da3 + dez * ac3 + aez * cd3)
           + deheighttail * (aez * bc3 - bez * ac3 + cez * ab3))
          - (aeheighttail * (bez * cd3 - cez * bd3 + dez * bc3)
           + ceheighttail * (dez * ab3 + aez * bd3 + bez * da3)));
  if ((det >= errbound) || (-det >= errbound)) {
    return det;
  }

  return orient4dexact(pa, pb, pc, pd, pe,
                       aheight, bheight, cheight, dheight, eheight);
}

starreal orient4d(struct behavior *b,
                  starreal *pa,
                  starreal *pb,
                  starreal *pc,
                  starreal *pd,
                  starreal *pe,
                  starreal aheight,
                  starreal bheight,
                  starreal cheight,
                  starreal dheight,
                  starreal eheight)
{
  starreal aex, bex, cex, dex;
  starreal aey, bey, cey, dey;
  starreal aez, bez, cez, dez;
  starreal aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey;
  starreal aexcey, cexaey, bexdey, dexbey;
  starreal aeheight, beheight, ceheight, deheight;
  starreal ab, bc, cd, da, ac, bd;
  starreal abc, bcd, cda, dab;
  starreal aezplus, bezplus, cezplus, dezplus;
  starreal aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus;
  starreal cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus;
  starreal aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus;
  starreal det;
  starreal permanent, errbound;

  b->orient4dcount++;

  aex = pa[0] - pe[0];
  bex = pb[0] - pe[0];
  cex = pc[0] - pe[0];
  dex = pd[0] - pe[0];
  aey = pa[1] - pe[1];
  bey = pb[1] - pe[1];
  cey = pc[1] - pe[1];
  dey = pd[1] - pe[1];
  aez = pa[2] - pe[2];
  bez = pb[2] - pe[2];
  cez = pc[2] - pe[2];
  dez = pd[2] - pe[2];
  aeheight = aheight - eheight;
  beheight = bheight - eheight;
  ceheight = cheight - eheight;
  deheight = dheight - eheight;

  aexbey = aex * bey;
  bexaey = bex * aey;
  ab = aexbey - bexaey;
  bexcey = bex * cey;
  cexbey = cex * bey;
  bc = bexcey - cexbey;
  cexdey = cex * dey;
  dexcey = dex * cey;
  cd = cexdey - dexcey;
  dexaey = dex * aey;
  aexdey = aex * dey;
  da = dexaey - aexdey;

  aexcey = aex * cey;
  cexaey = cex * aey;
  ac = aexcey - cexaey;
  bexdey = bex * dey;
  dexbey = dex * bey;
  bd = bexdey - dexbey;

  abc = aez * bc - bez * ac + cez * ab;
  bcd = bez * cd - cez * bd + dez * bc;
  cda = cez * da + dez * ac + aez * cd;
  dab = dez * ab + aez * bd + bez * da;

  det = (deheight * abc - ceheight * dab) + (beheight * cda - aeheight * bcd);

  if (b->noexact) {
    return det;
  }

  aezplus = Absolute(aez);
  bezplus = Absolute(bez);
  cezplus = Absolute(cez);
  dezplus = Absolute(dez);
  aexbeyplus = Absolute(aexbey);
  bexaeyplus = Absolute(bexaey);
  bexceyplus = Absolute(bexcey);
  cexbeyplus = Absolute(cexbey);
  cexdeyplus = Absolute(cexdey);
  dexceyplus = Absolute(dexcey);
  dexaeyplus = Absolute(dexaey);
  aexdeyplus = Absolute(aexdey);
  aexceyplus = Absolute(aexcey);
  cexaeyplus = Absolute(cexaey);
  bexdeyplus = Absolute(bexdey);
  dexbeyplus = Absolute(dexbey);
  permanent = ((cexdeyplus + dexceyplus) * bezplus
               + (dexbeyplus + bexdeyplus) * cezplus
               + (bexceyplus + cexbeyplus) * dezplus)
            * aeheight
            + ((dexaeyplus + aexdeyplus) * cezplus
               + (aexceyplus + cexaeyplus) * dezplus
               + (cexdeyplus + dexceyplus) * aezplus)
            * beheight
            + ((aexbeyplus + bexaeyplus) * dezplus
               + (bexdeyplus + dexbeyplus) * aezplus
               + (dexaeyplus + aexdeyplus) * bezplus)
            * ceheight
            + ((bexceyplus + cexbeyplus) * aezplus
               + (cexaeyplus + aexceyplus) * bezplus
               + (aexbeyplus + bexaeyplus) * cezplus)
            * deheight;
  errbound = isperrboundA * permanent;
  if ((det > errbound) || (-det > errbound)) {
    return det;
  }

  return orient4dadapt(pa, pb, pc, pd, pe,
                       aheight, bheight, cheight, dheight, eheight, permanent);
}

/*****************************************************************************/
/*                                                                           */
/*  nonregular()   Return a positive value if the point pe is incompatible   */
/*                 with the sphere or hyperplane passing through pa, pb, pc, */
/*                 and pd (meaning that pe is inside the sphere or below the */
/*                 hyperplane); a negative value if it is compatible; and    */
/*                 zero if the five points are cospherical/cohyperplanar.    */
/*                 The points pa, pb, pc, and pd must be ordered so that     */
/*                 they have a positive orientation (as defined by           */
/*                 orient3d()), or the sign of the result will be reversed.  */
/*                                                                           */
/*  If the -w switch is used, the points are lifted onto the parabolic       */
/*  lifting map, then they are adjusted according to their weights, then the */
/*  4D orientation test is applied.  If the -W switch is used, the points'   */
/*  heights are already provided, so the 4D orientation test is applied      */
/*  directly.  If neither switch is used, the insphere test is applied.      */
/*                                                                           */
/*****************************************************************************/

starreal nonregular(struct behavior *b,
                    starreal *pa,
                    starreal *pb,
                    starreal *pc,
                    starreal *pd,
                    starreal *pe)
{
  if (b->weighted == 0) {
    return insphere(b, pa, pb, pc, pd, pe);
  } else if (b->weighted == 1) {
    return orient4d(b, pa, pb, pc, pd, pe,
                    pa[0] * pa[0] + pa[1] * pa[1] + pa[2] * pa[2] - pa[3],
                    pb[0] * pb[0] + pb[1] * pb[1] + pb[2] * pb[2] - pb[3],
                    pc[0] * pc[0] + pc[1] * pc[1] + pc[2] * pc[2] - pc[3],
                    pd[0] * pd[0] + pd[1] * pd[1] + pd[2] * pd[2] - pd[3],
                    pe[0] * pe[0] + pe[1] * pe[1] + pe[2] * pe[2] - pe[3]);
  } else {
    return orient4d(b, pa, pb, pc, pd, pe, pa[3], pb[3], pc[3], pd[3], pe[3]);
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcircumcenter()   Find the circumcenter of a tetrahedron.              */
/*                                                                           */
/*  The result is returned both in terms of xyz coordinates and xi-eta-zeta  */
/*  coordinates, relative to the tetrahedron's apex (that is, the apex is    */
/*  the origin of both coordinate systems).  Hence, the xyz coordinates      */
/*  returned are NOT absolute; one must add the coordinates of the           */
/*  tetrahedron apex to find the absolute coordinates of the circumcircle.   */
/*  However, this means that the result is frequently more accurate than     */
/*  would be possible if absolute coordinates were returned, due to limited  */
/*  floating-point precision.                                                */
/*                                                                           */
/*  The xi-eta-zeta coordinate system is defined in terms of the             */
/*  tetrahedron:  the apex of the tetrahedron is the origin of the           */
/*  coordinate system.  The length from the apex to the origin of the        */
/*  tetrahedron is one unit along the xi axis.  The eta and zeta axes are    */
/*  defined similarly by the destination and face apex.                      */
/*                                                                           */
/*  If `xi' is NULL on input, the xi-eta-zeta coordinates will not be        */
/*  computed.                                                                */
/*                                                                           */
/*****************************************************************************/

void tetcircumcenter(struct behavior *b,
                     starreal *tetorg,
                     starreal *tetdest,
                     starreal *tetfapex,
                     starreal *tettapex,
                     starreal *circumcenter,
                     starreal *xi,
                     starreal *eta,
                     starreal *zeta)
{
  starreal xot, yot, zot, xdt, ydt, zdt, xft, yft, zft;
  starreal otlength, dtlength, ftlength;
  starreal xcrossdf, ycrossdf, zcrossdf;
  starreal xcrossfo, ycrossfo, zcrossfo;
  starreal xcrossod, ycrossod, zcrossod;
  starreal denominator;
  starreal xct, yct, zct;

  b->tetcircumcentercount++;

  /* Use coordinates relative to the apex of the tetrahedron. */
  xot = tetorg[0] - tettapex[0];
  yot = tetorg[1] - tettapex[1];
  zot = tetorg[2] - tettapex[2];
  xdt = tetdest[0] - tettapex[0];
  ydt = tetdest[1] - tettapex[1];
  zdt = tetdest[2] - tettapex[2];
  xft = tetfapex[0] - tettapex[0];
  yft = tetfapex[1] - tettapex[1];
  zft = tetfapex[2] - tettapex[2];
  /* Squares of lengths of the origin, destination, and face apex edges. */
  otlength = xot * xot + yot * yot + zot * zot;
  dtlength = xdt * xdt + ydt * ydt + zdt * zdt;
  ftlength = xft * xft + yft * yft + zft * zft;
  /* Cross products of the origin, destination, and face apex vectors. */
  xcrossdf = ydt * zft - yft * zdt;
  ycrossdf = zdt * xft - zft * xdt;
  zcrossdf = xdt * yft - xft * ydt;
  xcrossfo = yft * zot - yot * zft;
  ycrossfo = zft * xot - zot * xft;
  zcrossfo = xft * yot - xot * yft;
  xcrossod = yot * zdt - ydt * zot;
  ycrossod = zot * xdt - zdt * xot;
  zcrossod = xot * ydt - xdt * yot;

  /* Calculate the denominator of all the formulae. */
  if (b->noexact) {
    denominator = 0.5 / (xot * xcrossdf + yot * ycrossdf + zot * zcrossdf);
  } else {
    /* Use the orient3d() routine to ensure a positive (and    */
    /*   reasonably accurate) result, avoiding any possibility */
    /*   of division by zero.                                  */
    denominator = 0.5 / orient3d(b, tetorg, tetdest, tetfapex, tettapex);
    /* Don't count the above as an orientation test. */
    b->orientcount--;
  }

  /* Calculate offset (from apex) of circumcenter. */
  xct = (otlength * xcrossdf + dtlength * xcrossfo + ftlength * xcrossod) *
        denominator;
  yct = (otlength * ycrossdf + dtlength * ycrossfo + ftlength * ycrossod) *
        denominator;
  zct = (otlength * zcrossdf + dtlength * zcrossfo + ftlength * zcrossod) *
        denominator;
  circumcenter[0] = xct;
  circumcenter[1] = yct;
  circumcenter[2] = zct;

  if (xi != (starreal *) NULL) {
    /* To interpolate vertex attributes for the new vertex inserted at */
    /*   the circumcenter, define a coordinate system with a xi-axis,  */
    /*   directed from the tetrahedron's apex to its origin, an        */
    /*   eta-axis, directed from its apex to its destination, and a    */
    /*   zeta-axis, directed from its apex to its face apex.   The     */
    /*   values for xi, eta, and zeta are computed by Cramer's Rule    */
    /*   for solving systems of linear equations.                      */
    *xi = (xct * xcrossdf + yct * ycrossdf + zct * zcrossdf) *
          (2.0 * denominator);
    *eta = (xct * xcrossfo + yct * ycrossfo + zct * zcrossfo) *
           (2.0 * denominator);
    *zeta = (xct * xcrossod + yct * ycrossod + zct * zcrossod) *
            (2.0 * denominator);
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tricircumcenter3d()   Find the circumcenter of a triangle in 3D.         */
/*                                                                           */
/*  The result is returned both in terms of xyz coordinates and xi-eta       */
/*  coordinates, relative to the triangle's apex (that is, the apex is the   */
/*  origin of both coordinate systems).  Hence, the xyz coordinates returned */
/*  are NOT absolute; one must add the coordinates of the apex to find the   */
/*  absolute coordinates of the circumcircle.  However, this means that the  */
/*  result is frequently more accurate than would be possible if absolute    */
/*  coordinates were returned, due to limited floating-point precision.  In  */
/*  particular, the result can be used for a more accurate calculation of    */
/*  the radius of the triangle's circumcirle.                                */
/*                                                                           */
/*  The xi-eta coordinate system is defined in terms of the triangle:  the   */
/*  apex of the triangle is the origin of the coordinate system.  The length */
/*  from the apex to the origin of the triangle is one unit along the xi     */
/*  axis.  The length from the apex to the destination is one unit along the */
/*  eta axis.                                                                */
/*                                                                           */
/*  A normal vector to the triangle is returned in `normal'.  This vector is */
/*  a cross product of two of the triangle's edge, so its length is twice    */
/*  the triangle's area.  It points up from the face (assuming the triangle  */
/*  lies with its origin, destination, and apex in counterclockwise order).  */
/*                                                                           */
/*  If `normal' is NULL on input, the normal will not be returned.           */
/*  If `xi' is NULL on input, the xi-eta coordinates will not be computed.   */
/*                                                                           */
/*****************************************************************************/

void tricircumcenter3d(struct behavior *b,
                       starreal *triorg,
                       starreal *tridest,
                       starreal *triapex,
                       starreal *circumcenter,
                       starreal *normal,
                       starreal *xi,
                       starreal *eta)
{
  starreal xoa, yoa, zoa, xda, yda, zda;
  starreal oalength, dalength;
  starreal xcrossod, ycrossod, zcrossod;
  starreal denominator;
  starreal xca, yca, zca;

  b->tricircumcentercount++;

  /* Use coordinates relative to the apex of the triangle. */
  xoa = triorg[0] - triapex[0];
  yoa = triorg[1] - triapex[1];
  zoa = triorg[2] - triapex[2];
  xda = tridest[0] - triapex[0];
  yda = tridest[1] - triapex[1];
  zda = tridest[2] - triapex[2];
  /* Squares of lengths of the origin and destination edges. */
  oalength = xoa * xoa + yoa * yoa + zoa * zoa;
  dalength = xda * xda + yda * yda + zda * zda;
  
  /* Cross product of the origin and destination vectors. */
  if (b->noexact) {
    xcrossod = yoa * zda - yda * zoa;
    ycrossod = zoa * xda - zda * xoa;
    zcrossod = xoa * yda - xda * yoa;
  } else {
    /* Use the orient2d() routine to ensure a nonzero (and     */
    /*   reasonably accurate) result, avoiding any possibility */
    /*   of division by zero.                                  */
    xcrossod = orient2d(b, triorg[1], triorg[2], tridest[1], tridest[2],
                        triapex[1], triapex[2]);
    ycrossod = orient2d(b, triorg[2], triorg[0], tridest[2], tridest[0],
                        triapex[2], triapex[0]);
    zcrossod = orient2d(b, triorg[0], triorg[1], tridest[0], tridest[1],
                        triapex[0], triapex[1]);
  }
  /* Calculate the denominator of the circumcenter. */
  denominator = 0.5 / (xcrossod * xcrossod + ycrossod * ycrossod +
                       zcrossod * zcrossod);

  /* Calculate offset (from apex) of circumcenter. */
  xca = ((oalength * yda - dalength * yoa) * zcrossod -
         (oalength * zda - dalength * zoa) * ycrossod) * denominator;
  yca = ((oalength * zda - dalength * zoa) * xcrossod -
         (oalength * xda - dalength * xoa) * zcrossod) * denominator;
  zca = ((oalength * xda - dalength * xoa) * ycrossod -
         (oalength * yda - dalength * yoa) * xcrossod) * denominator;
  circumcenter[0] = xca;
  circumcenter[1] = yca;
  circumcenter[2] = zca;

  if (normal != (starreal *) NULL) {
    normal[0] = xcrossod;
    normal[1] = ycrossod;
    normal[2] = zcrossod;
  }

  if (xi != (starreal *) NULL) {
    /* To interpolate vertex attributes for the new vertex inserted at */
    /*   the circumcenter, define a coordinate system with a xi-axis,  */
    /*   directed from the tetrahedron's apex to its origin, and an    */
    /*   eta-axis, directed from its apex to its destination.  The     */
    /*   values for xi and eta are computed by Cramer's Rule for       */
    /*   solving systems of linear equations.                          */

    /* There are three ways to do this calculation - using xcrossod, */
    /*   ycrossod, or zcrossod.  Choose whichever has the largest    */
    /*   magnitude, to improve stability and avoid division by zero. */
    if (((xcrossod >= ycrossod) ^ (-xcrossod > ycrossod)) &&
        ((xcrossod >= zcrossod) ^ (-xcrossod > zcrossod))) {
      *xi = (yca * zda - yda * zca) / xcrossod;
      *eta = (yoa * zca - yca * zoa) / xcrossod;
    } else if ((ycrossod >= zcrossod) ^ (-ycrossod > zcrossod)) {
      *xi = (zca * xda - zda * xca) / ycrossod;
      *eta = (zoa * xca - zca * xoa) / ycrossod;
    } else {
      *xi = (xca * yda - xda * yca) / zcrossod;
      *eta = (xoa * yca - xca * yoa) / zcrossod;
    }
  }
}

/**                                                                         **/
/**                                                                         **/
/********* Geometric primitives end here                             *********/


/********* Tetrahedral complex routines begin here                   *********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  Space-efficient tetrahedral complexes (struct tetcomplex)                */
/*                                                                           */
/*  Roughly speaking, a tetrahedral complex (as it is implemented here) is   */
/*  a set of tetrahedra that follow the rules of simplicial complexes.  It   */
/*  cannot represent a three-dimensional simplicial complex with full        */
/*  generality, though, because it does not (fully) support the presence of  */
/*  edges or triangles that are not faces of any tetrahedron.                */
/*                                                                           */
/*  The tetcomplex procedures are purely topological, which means that none  */
/*  of them ever looks at the coordinates of a vertex (or even knows how     */
/*  vertices are represented).  A tetrahedron is denoted by the labels of    */
/*  its four vertices, which are integer tags (that is, the `tag' type       */
/*  defined for proxipools).  The tetcomplex procedures take and return      */
/*  vertex tags (not data structures that represent vertices).               */
/*                                                                           */
/*  Every tetrahedron has an orientation, implied by the order of its        */
/*  vertices.  A tetrahedron can be oriented two ways.  All even             */
/*  permutations of a tetrahedron's vertices are considered equivalent       */
/*  (having the same orientation), and all odd permutations of a             */
/*  tetrahedron's vertices have the opposite orientation (but are equivalent */
/*  to each other).  So (1, 2, 3, 4) = (2, 1, 4, 3) = (1, 4, 2, 3), but      */
/*  (1, 2, 3, 4) is opposite to (1, 2, 4, 3).  Typically, topological        */
/*  orientation echoes geometrical orientation according to a right-hand     */
/*  rule:  the orientation (1, 2, 3, 4) implies that the vertices 2, 3, 4    */
/*  occur in counterclockwise order as seen from vertex 1.  If you curl the  */
/*  fingers of your right hand to follow the vertices 2, 3, 4, then your     */
/*  thumb points toward vertex 1.                                            */
/*                                                                           */
/*  You could use the left-hand rule (a mirror image) instead, and this data */
/*  structure won't know the difference.  However, all the tetrahedron       */
/*  orientations must agree!  This data structure does not support complexes */
/*  in which the tetrahedron orientations are mixed.                         */
/*                                                                           */
/*  The data structure is designed to support tetrahedral complexes in       */
/*  three-dimensional space.  One rule is that each triangle may be a face   */
/*  of at most two tetrahedra.  In other words, for any triple of vertices,  */
/*  only two tetrahedra can have all three of those vertices.  (This rules   */
/*  out general tetrahedral complexes in four-dimensional space.)            */
/*                                                                           */
/*  Another rule is that if two tetrahedra share a triangular face, their    */
/*  orientations must be such that the tetrahedra are on opposite sides of   */
/*  the face.  For example, the tetrahedra (1, 2, 3, 4) and (1, 3, 2, 5) can */
/*  coexist in a tetcomplex, but (1, 2, 3, 4) and (1, 2, 3, 5) cannot.       */
/*                                                                           */
/*  The data structure supports the insertion of tetrahedra, so long as they */
/*  obey these rules.  It supports the deletion of any tetrahedra in the     */
/*  complex.  There are also procedures for performing common bistellar      */
/*  flips.                                                                   */
/*                                                                           */
/*  The main query is a "triangle query", which takes three vertices         */
/*  (representing a triangle) as input, and returns the two tetrahedra       */
/*  adjoining the triangle, represented by the fourth vertex of each         */
/*  tetrahedron.  The absence of one (or both) of these tetrahedra is        */
/*  indicated by a value of GHOSTVERTEX as the fourth vertex.  If the        */
/*  triangle itself is missing from the complex, the return value indicates  */
/*  that.                                                                    */
/*                                                                           */
/*  There are also specialized procedures designed to help the Bowyer-Watson */
/*  algorithm for incremental insertion in Delaunay triangulations run fast. */
/*                                                                           */
/*  Public interface:                                                        */
/*  struct tetcomplex   Represents a tetrahedral complex.                    */
/*  struct tetcomplexstar   Holds information about one vertex's 2D link.    */
/*  struct tetcomplexposition   Represents a position for iterating through  */
/*    the tetrahedra in a complex.                                           */
/*  tetcomplexinit(plex, vertexpool, verbose)   Initialize a tetcomplex.     */
/*  tetcomplexrestart(plex)   Erase all tetrahedra.                          */
/*  tetcomplexdeinit(plex)   Free a tetcomplex's memory to the OS.           */
/*  tetcomplextag2vertex(plex, searchtag)   Map a tag to a pointer that      */
/*    points at a vertex data structure.  Unsafe; fast macro.                */
/*  tetcomplextag2attributes(plex, searchtag)   Map a tag to a pointer at    */
/*    the attributes associated with a vertex.  Unsafe; fast macro.          */
/*  tetcomplexadjacencies(plex, vtx1, vtx2, vtx3, adjacencies[2])   Find the */
/*    tetrahedra adjoining the triangle (vtx1, vtx2, vtx3).                  */
/*  tetcomplexiteratorinit(plex, pos)   Initialize an iterator over the      */
/*    tetrahedra of the complex.                                             */
/*  tetcomplexiterate(pos, nexttet[4])   Return the next tetrahedron,        */
/*    excluding duplicates.  Certain ghosts are included.                    */
/*  tetcomplexiteratenoghosts(pos, nexttet[4])   Return the next             */
/*    tetrahedron, excluding duplicates and ghosts.                          */
/*  tetcomplexprint(plex)   Print the tetrahedra in a tetcomplex.            */
/*  tetcomplexprintstars(plex)   Print the stars in a tetcomplex.            */
/*  tetcomplexconsistency(plex)   Check internal consistency of tetcomplex.  */
/*  tetcomplexdeletetet(plex, vtx1, vtx2, vtx3, vtx4)   Delete a             */
/*    tetrahedron.                                                           */
/*  tetcomplexinserttet(plex, vtx1, vtx2, vtx3, vtx4)   Insert a             */
/*    tetrahedron.                                                           */
/*  tetcomplex14flip(plex, vtx1, vtx2, vtx3, vtx4, newvertex)   Replace one  */
/*    tetrahedron with four by lazily inserting `newvertex'.                 */
/*  tetcomplex23flip(plex, vtxtop, vtx1, vtx2, vtx3, vtxbot)   Replace two   */
/*    tetrahedra with three (bistellar flip).                                */
/*  tetcomplex32flip(plex, vtxtop, vtx1, vtx2, vtx3, vtxbot)   Replace three */
/*    tetrahedra with two (bistellar flip).  Inverse of tetcomplex23flip.    */
/*  tetcomplex41flip(plex, vtx1, vtx2, vtx3, vtx4, deletevertex)   Replace   */
/*    four tetrahedra with one.  Inverse of tetcomplex14flip.                */
/*  tetcomplexremoveghosttets(plex)   Remove all the ghost tetrahedra.       */
/*  tetcomplextetcount(plex)   Return number of tetrahedra (no ghosts).      */
/*  tetcomplexghosttetcount(plex)   Return number of explicity inserted      */
/*    ghost tetrahedra.                                                      */
/*  tetcomplexbytes(plex)   Return bytes used by the complex.                */
/*                                                                           */
/*  For algorithms that use inconsistent stars (e.g. star splaying):         */
/*  tetcomplexringadjacencies(plex, vtx1, vtx2, vtx3, adjacencies[2])        */
/*    Search the star of (vtx1, vtx2) to try to find the tetrahedra          */
/*    adjoining the triangle (vtx1, vtx2, vtx3).                             */
/*  tetcomplexiterateall(pos, nexttet[4])   Return the next tetrahedron,     */
/*    with duplicate copies included.  Certain ghosts are included.          */
/*  tetcomplexdeleteorderedtet(plex, vtx1, vtx2, vtx3, vtx4)   Delete an     */
/*    ordered tetrahedron.                                                   */
/*  tetcomplexinsertorderedtet(plex, vtx1, vtx2, vtx3, vtx4)   Insert an     */
/*    ordered tetrahedron.                                                   */
/*  tetcomplex12fliponedge(plex, vtx1, vtx2, vtx3, vtx4, newvertex)          */
/*    Replace (vtx1, vtx2, vtx3, vtx4) with (vtx1, vtx2, vtx3, newvertex)    */
/*    and (vtx1, vtx2, newvertex, vtx4) in the star of (vtx1, vtx2).         */
/*  tetcomplex21fliponedge(plex, vtx1, vtx2, vtx3)   Replace (vtx1,          */
/*    vtx2, ?, vtx3) and (vtx1, vtx2, vtx3, ??) with (vtx1, vtx2, ?, ??) in  */
/*    the star of (vtx1, vtx2).                                              */
/*                                                                           */
/*  Specialized for the Bowyer-Watson algorithm:                             */
/*  tetcomplexinserttetontripod(plex, vtx1, vtx2, vtx3, vtx4)   Insert a     */
/*    tetrahedron into the stars of 3 edges that meet at `vtx1'.             */
/*  tetcomplexdeletetriangle(plex, vtx1, vtx2, vtx3)   Delete a triangle,    */
/*    gluing two tetrahedra into a polyhedron.                               */
/*  tetcomplexsqueezetriangle(plex, vtx1, vtx2, vtx3)   Delete a triangle    */
/*    that has the new vertex on both sides of it.                           */
/*  tetcomplexbuild3dstar(plex, newvertex, trianglelist, firstindex,         */
/*    trianglecount)   Convert a 2D link triangulation made up of `struct    */
/*    tetcomplexlinktriangle' triangles to the native data structure.        */
/*                                                                           */
/*  For internal use only:                                                   */
/*  tetcomplexlookup3dstar(plex, vtx)                                        */
/*  tetcomplexmissingtet(plex, vtx1, vtx2, vtx3, vtx4)                       */
/*                                                                           */
/*****************************************************************************/

/*****************************************************************************/
/*                                                                           */
/*  Ghost tetrahedra                                                         */
/*                                                                           */
/*  A ghost tetrahedron is a tetrahedron that has the GHOSTVERTEX for one of */
/*  its vertices.  A solid tetrahedron is a tetrahedron whose vertices are   */
/*  all not GHOSTVERTEX.  Except in one special case, tetrahedra with two    */
/*  ghost vertices are prohibited.                                           */
/*                                                                           */
/*  Ghost tetrahedra are implicitly returned by the face adjacency query.    */
/*  For example, if you query the identity of the two tetrahedra adjoining   */
/*  the triangle (1, 2, 3), and the tetrahedron (1, 2, 3, 4) is the sole     */
/*  tetrahedron in the entire complex, the query will return GHOSTVERTEX and */
/*  4, indicating that the triangle adjoins the tetrahedra (1, 2, 3, 4) and  */
/*  (1, 3, 2, GHOSTVERTEX).  However, this does not mean that the latter     */
/*  tetrahedron was ever inserted into the tetcomplex.                       */
/*                                                                           */
/*  However, it is permissible to insert ghost tetrahedra into a tetcomplex, */
/*  and they will (usually) be stored therein, if they obey the same rules   */
/*  that solid tetrahedra obey about sharing faces.  Why would you want to   */
/*  do this?  Because they make it easier to navigate along the boundary of  */
/*  a complex.  This takes a bit of explanation...                           */
/*                                                                           */
/*  A ghost triangle is a triangle that has the GHOSTVERTEX for one of its   */
/*  vertices.  Suppose you know that the edge (1, 2) is on the boundary of   */
/*  the mesh, and you want to find the identity of the boundary triangles    */
/*  that have it for an edge.  Suppose these triangles are (1, 2, 3) and     */
/*  (2, 1, 4).  Because they are boundary triangles, you might think that    */
/*  you could query the identity of the tetrahedra that adjoin the ghost     */
/*  triangle (1, 2, GHOSTVERTEX).  Ideally, the query would return the       */
/*  tetrahedra (1, 2, GHOSTVERTEX, 3) and (1, GHOSTVERTEX, 2, 4), thereby    */
/*  answering the question of which boundary triangles adjoin (1, 2).        */
/*                                                                           */
/*  One of the disadvantages of the space-efficient data structure is that   */
/*  this query doesn't always find the desired ghost tetrahedra.  (Sometimes */
/*  it does; sometimes it doesn't.)  However, if the ghost tetrahedra are    */
/*  _explicitly_ inserted into the tetcomplex (at the cost of taking up      */
/*  extra memory), adjacency queries on ghost triangles are answered         */
/*  reliably.  For this to work, you must insert one ghost tetrahedron for   */
/*  every triangular face on the boundary of the tetrahedralization.  This   */
/*  makes it possible, for example, to efficiently "walk" along the boundary */
/*  of the tetrahedralization.                                               */
/*                                                                           */
/*  There are some oddities to explicitly stored ghost tetrahedra, though.   */
/*  First, they are independent of the solid tetrahedra stored in the        */
/*  tetcomplex.  The tetcomplex won't notice if the solid tetrahedra and     */
/*  ghost tetrahedra are completely inconsistent with each other.  It's the  */
/*  caller's responsibility to keep them consistent, because the tetcomplex  */
/*  doesn't check.                                                           */
/*                                                                           */
/*  All adjacency queries on solid triangles are answered using the solid    */
/*  tetrahedra; stored ghost tetrahedra have no influence on these queries.  */
/*  Adjacency queries on ghost triangles are answered using a combination    */
/*  of ghost and solid tetrahedra.  If the ghost tetrahedra are not          */
/*  consistent with the solid tetrahedra, these queries may be answered      */
/*  inconsistently.                                                          */
/*                                                                           */
/*  Second, imagine that two solid tetrahedra (1, 2, 3, 4) and (1, 2, 5, 6)  */
/*  share a boundary edges (1, 2), but no other tetrahedra do.  So there are */
/*  actually four boundary triangles sharing the edge.  (The boundary of the */
/*  tetrahedral complex is nonmanifold.)  If you try to explicitly store a   */
/*  ghost tetrahedron for each of these boundary faces, then you have four   */
/*  ghost tetrahedra sharing the face (1, 2, GHOSTVERTEX).  This is not      */
/*  allowed; only two ghost tetrahedra may share a ghost triangle.  So       */
/*  explicitly stored ghost tetrahedra only really make sense for a          */
/*  tetrahedralization covering a (nondegenerate) convex polyhedron.  They   */
/*  don't make sense for a general-purpose mesh.                             */
/*                                                                           */
/*  Third, it isn't really possible to determine whether a tetcomplex        */
/*  contains a particular ghost tetrahedron or not.  For example, if a solid */
/*  tetrahedron (1, 2, 3, 4) is present, then queries on the faces (1, 2, 3) */
/*  or (1, 2, GHOSTVERTEX) might both indicate the presence of a tetrahedron */
/*  (1, 3, 2, GHOSTVERTEX), but that doesn't tell you whether that           */
/*  tetrahedron is explicitly stored or not.                                 */
/*                                                                           */
/*  Fourth, sometimes the insertion (or deletion) of a ghost tetrahedron     */
/*  doesn't actually change the data structure at all--except for the count  */
/*  of ghost tetrahedra.  This is because of the unusual nature of the       */
/*  space-efficient tetrahedral complex data structure:  it might not store  */
/*  the link of any of the tetrahedron's edges adjoining the GHOSTVERTEX.    */
/*  With these tetrahedra, an application might be able to corrupt the count */
/*  of ghost tetrahedra by inserting (or deleting) the same ghost            */
/*  tetrahedron twice.                                                       */
/*                                                                           */
/*  Despite all these quirks, explicitly stored ghost tetrahedra can be very */
/*  useful.  My implementation of the Bowyer-Watson algorithm for            */
/*  incremental vertex insertion in Delaunay triangulations uses them        */
/*  because it simplifies the algorithm in several ways:  by making it       */
/*  possible to treat inserting a vertex outside the convex hull much the    */
/*  same as inserting a vertex inside the tetrahedralization, and by making  */
/*  it easy to walk along the boundary of the tetrahedralization (which is   */
/*  important when a vertex is inserted outside the convex hull).            */
/*  Nevertheless, it's simpler to use the tetcomplex data structure if you   */
/*  don't explicitly store ghost tetrahedra.                                 */
/*                                                                           */
/*****************************************************************************/

/*****************************************************************************/
/*                                                                           */
/*  The memory-efficient data structure                                      */
/*  (Blandford, Blelloch, Cardoze, and Kadow)                                */
/*                                                                           */
/*  The tetcomplex structure represents a tetrahedral complex as a set of    */
/*  _stars_.  The star of a vertex is the set of simplices that adjoin the   */
/*  vertex.  The star of an edge is the set of simplices that have the edge  */
/*  for a face (i.e. simplices that share both of the edge's vertices).      */
/*                                                                           */
/*  The _link_ of a vertex is the set of simplices that don't adjoin the     */
/*  vertex, but are faces of simplices in the vertex's star.  For example,   */
/*  if vertex 1 adjoins just two tetrahedra, (1, 2, 3, 4) and (1, 3, 2, 5),  */
/*  then its link is the set { (2), (3), (4), (5), (2, 3), (2, 4), (3, 4),   */
/*  (2, 5), (3, 5), (2, 3, 4), (3, 2, 5) }.  Because the tetcomplex data     */
/*  structure does not support edges or triangles that aren't faces of       */
/*  tetrahedra, you can specify the link of a vertex simply by specifying    */
/*  the triangles--in this case, (2, 3, 4) and (3, 2, 5).                    */
/*                                                                           */
/*  The link of an edge is the set of simplices that don't adjoin either of  */
/*  the edge's vertices, but are faces of simplices in the edge's star.  In  */
/*  the previous example, the link of (1, 2) is { (3), (4), (5), (3, 4),     */
/*  (3, 5) }.  You can specify the link of an edge simply by specifying the  */
/*  edges--in this case, (3, 4) and (3, 5).  The link of an edge is either a */
/*  ring of edges, or a (possibly empty) sequence of chains of edges.        */
/*                                                                           */
/*  A data structure that represents the link of a vertex implicitly         */
/*  represents the star of the vertex as well, and vice versa.  (The star is */
/*  three-dimensional, because it includes tetrahedra, and the link is two-  */
/*  dimensional, because its highest-dimensional simplices are triangles.)   */
/*  Likewise, an edge's link implies its star, and vice versa.  (The star is */
/*  three-dimensional, but the link is only one-dimensional, because its     */
/*  highest-dimensional simplices are edges.)                                */
/*                                                                           */
/*  The tetcomplex data structure uses a `tetcomplexstar' to represent the   */
/*  star of a vertex.  The tetcomplexstar references (using a tag) a link2d  */
/*  data structure, which simultaneously represents the 2D link and the 3D   */
/*  star.  Each link2d contains a list of edges and their stars, represented */
/*  by the linkring data structure, which simultaneously represents the 1D   */
/*  link and the 3D star.  (Both the link2d and linkring data structures are */
/*  described in separate headers like this one.)  The link2d and linkring   */
/*  data structures store tags in a compressed form, helping to make the     */
/*  tetcomplex data structure occupy less space.                             */
/*                                                                           */
/*  However, that's not the only trick Blandford et al. use to save space.   */
/*  At first sight, the star representation of a tetrahedral complex might   */
/*  seem to store a lot of redundant information, because each tetrahedron   */
/*  is in the star of four different vertices; and within one vertex's star, */
/*  each tetrahedron is in the star of three different edges.  So is each    */
/*  tetrahedron stored twelve times?                                         */
/*                                                                           */
/*  No.  On average, each tetrahedron is stored just three times, because    */
/*  of the following two optimizations of Blandford et al.                   */
/*                                                                           */
/*  (1)  If a tetcomplex contains an edge (a, b), the link ring for that     */
/*       edge is stored only if a and b have the same parity--in other       */
/*       words, if both are odd or both are even.  (If a and b have opposite */
/*       parity, the edge's link must be deduced by looking at other edges'  */
/*       links.)  This cuts the memory occupied by link rings in half.       */
/*       Note that the GHOSTVERTEX has odd parity.                           */
/*                                                                           */
/*  (2)  If a tetcomplex contains an edge (a, b), where a and b have the     */
/*       same parity, the link ring for edge (a, b) is stored in one         */
/*       vertex's star--either the star for a or the star for b, but not     */
/*       both.  If one of the vertices is the GHOSTVERTEX, then the edge's   */
/*       link ring is stored in the other vertex's star.  (The GHOSTVERTEX   */
/*       does not get a star.)  Otherwise, if both vertices have the same    */
/*       two's bit, the edge's link ring is stored in the star of the vertex */
/*       with the greater index.  If the vertices have opposite two's bits,  */
/*       the edge's link is stored with the vertex with the lesser index.    */
/*       This cuts the memory occupied by link rings in half.                */
/*                                                                           */
/*       Why such a complicated rule?  I could have simply stored every      */
/*       edge's link with the vertex with the lesser index (which is what    */
/*       Blandford et al. do).  But then vertices with small indices would   */
/*       tend to have a lot of link rings stored in their stars, and         */
/*       vertices with large indices would tend to have few or none.  But    */
/*       the overall amount of time a program spends searching through a     */
/*       vertex's star is probably quadratic in the number of link rings it  */
/*       stores, so it's better to distribute link rings among vertices in a */
/*       pseudorandom way.  Moreover, fewer vertices will have empty stars,  */
/*       so the operation of finding some tetrahedron that adjoins a vertex  */
/*       is usually faster.                                                  */
/*                                                                           */
/*  Even with these optimizations, the tetcomplex data structure supports    */
/*  fast triangle queries.  Suppose you query the identity of the two        */
/*  tetrahedra adjoining the triangle (a, b, c).  At least two of those      */
/*  three vertices must have the same parity.  Suppose a and c have the same */
/*  parity.  The query is answered by a search through the link ring of the  */
/*  edge (a, c), which is stored either in a's star or in c's star.          */
/*                                                                           */
/*  The disadvantage of these optimizations is that it is not always         */
/*  efficient to answer the queries "find a tetrahedron that adjoins vertex  */
/*  a" or "find a tetrahedron that has the edge (a, b)".  In the worst case, */
/*  these queries might require an exhaustive search through the entire      */
/*  tetcomplex.  Therefore, these queries should be used as little as        */
/*  possible.  Fortunately, incremental Delaunay triangulation and many      */
/*  other algorithms can be implemented without these queries.               */
/*                                                                           */
/*  Ghost tetrahedra inserted into a tetcomplex are stored in the link rings */
/*  of ghost edges.  Inserting or deleting a ghost tetrahedron does not      */
/*  modify any solid edges' link rings.  However, triangle queries on ghost  */
/*  triangles sometimes use ghost edges' link rings, and sometimes solid     */
/*  edges' link rings, to answer those queries.  For example, a query on the */
/*  triangle (2, 4, GHOSTVERTEX) will consult the edge (2, 4), because the   */
/*  GHOSTVERTEX has odd parity, and no link ring is stored for               */
/*  (2, GHOSTVERTEX) or (4, GHOSTVERTEX).  That's why these queries may be   */
/*  answered incorrectly if the ghost tetrahedra are not consistent with the */
/*  solid tetrahedra.                                                        */
/*                                                                           */
/*  Solid tetrahedra inserted into a tetcomplex are stored in the link rings */
/*  of solid edges.  Inserting or deleting a solid tetrahedron does not      */
/*  modify any ghost edges' link rings.  Triangle queries on solid triangles */
/*  never consult ghost edges' link rings.                                   */
/*                                                                           */
/*****************************************************************************/


/*  A tetcomplex is a tetrahedral complex data structure.  It is composed of */
/*  a set of 3D stars, one for each vertex.  These stars have type `struct   */
/*  tetcomplexstar', and are stored (referenced by vertex tag) through the   */
/*  array `stars'.  The molecules that the stars are composed of are stored  */
/*  in the memory pool `moleculepool'.  All of the stars in `stars' having   */
/*  index less than `nextinitindex' have been initialized, and all the stars */
/*  having index `nextinitindex' or greater have not.                        */
/*                                                                           */
/*  Each tetcomplex has a pointer `vertexpool' to the memory pool in which   */
/*  the complex's vertices are stored.  One set of vertices can be shared by */
/*  any number of tetcomplexes.  Recall that no tetcomplex procedure ever    */
/*  looks at the coordinates of a vertex.  So what is `vertexpool' for?      */
/*  First, it is used to look up allocation indices; the molecules that make */
/*  up a vertex's star are allocated using the same allocation index that    */
/*  was used to allocate the vertex itself.  Second, the procedures          */
/*  `tetcomplextag2vertex' and `tetcomplextag2attributes' are provided to    */
/*  clients, so that clients can look up vertices without having to remember */
/*  which vertices go with which tetcomplex (and perhaps getting it wrong!). */
/*                                                                           */
/*  `tetcount' is the number of solid tetrahedra in the complex, and         */
/*  `ghosttetcount' is the number of ghost tetrahedra.  These counts are not */
/*  guaranteed to be preserved correctly by all operations.  In particular,  */
/*  if the stars become mutually inconsistent during star splaying, these    */
/*  counts will become wrong.  (When the stars are inconsistent with each    */
/*  other, you can't meaningfully say how many tetrahedra there are.)  Also, */
/*  sometimes inserting or removing a ghost tetrahedron doesn't change the   */
/*  data structure at all (except the count of ghost tetrahedra), so         */
/*  `ghosttetcount' is maintained primarily by counting the tetrahedra       */
/*  inserted or removed by the calling application, and can be fooled if the */
/*  application adds or removes a ghost tetrahedron whose absence or         */
/*  presence the tetcomplex cannot verify.                                   */
/*                                                                           */
/*  `consistentflag' indicates whether the stars are (believed to be)        */
/*  mutually consistent.                                                     */
/*                                                                           */
/*  The number `verbosity' indicates how much debugging information to       */
/*  print, from none (0) to lots (4+).                                       */

struct tetcomplex {
  struct proxipool moleculepool;     /* Pool of molecules storing the links. */
  struct arraypool stars;    /* `tetcomplexstar' array addressing the links. */
  struct proxipool *vertexpool;                     /* The pool of vertices. */
  tag nextinitindex;      /* First uninitialized index in the `stars' array. */
  arraypoolulong tetcount;           /* Number of tetrahedra in the complex. */
  arraypoolulong ghosttetcount;          /* Ghost tetrahedra in the complex. */
  int consistentflag;           /* Are the stars consistent with each other? */
  int verbosity;                /* Amount of debugging information to print. */
  link2dcache cache;                  /* Cache for fast lookups in 2D links. */
};

/*  A tetcomplexstar addresses a vertex's 3D star, represented by a 2D link, */
/*  stored as a link2d data structure.  `linkhead' and `linktail' are tags   */
/*  referencing the first and last molecules, respectively, of the link2d    */
/*  linked list.  The tail is stored to make `link2dinsertvertex' fast.      */

struct tetcomplexstar {
  tag linkhead;                 /* First molecule of the link2d linked list. */
  tag linktail;                  /* Last molecule of the link2d linked list. */
};

/*  A tetcomplexposition represents a position in a tetrahedral complex, and */
/*  is used to iterate over all the tetrahedra in the complex.               */

struct tetcomplexposition {
  struct tetcomplex *mycomplex;          /* The complex this position is in. */
  tag starvertex;     /* The vertex whose star is currently being traversed. */
  struct link2dposition link2dposition;            /* That vertex's 2D link. */
  tag link2dvertex;                  /* Vertex in 2D link, denoting an edge. */
  struct linkposition link1dposition;           /* That edge's 1D link ring. */
  tag link1dfirstvertex;    /* First vertex in ring (needed at end of ring). */
  tag link1dprevvertex;                 /* Vertex visited on last iteration. */
};

/*  The tetcomplexlinktriangle struct is part of the interface of            */
/*  tetcomplexbuild3dstar().  The procedure takes as input a complete 2D     */
/*  link made up of tetcomplexlinktriangles linked together, and converts    */
/*  them into link rings and a 2D link.                                      */

struct tetcomplexlinktriangle {
  tag vtx[3];
  arraypoolulong neighbor[3];
};


/*****************************************************************************/
/*                                                                           */
/*  tetcomplexinit()   Initialize an empty tetrahedral complex.              */
/*                                                                           */
/*  Before a tetcomplex may be used, it must be initialized by this          */
/*  procedure.                                                               */
/*                                                                           */
/*  The optional `vertexpool' parameter has two purposes.  First, it allows  */
/*  the tetcomplex to look up the allocation indices of the vertices, and    */
/*  use the same allocation indices to allocate the data structures used to  */
/*  store the vertices' links.  Thus, if vertices that are geometrically     */
/*  close to each other tend to have the same allocation indices, then the   */
/*  same will be true for the link data structures.  Second, it enables the  */
/*  fast macros tetcomplextag2vertex() and tetcomplextag2attributes(), which */
/*  directly map a vertex tag to a vertex data structure.  These save the    */
/*  programmer from having to remember which vertexpool goes with the        */
/*  tetcomplex.                                                              */
/*                                                                           */
/*  If you are not storing vertex data structures in a proxipool (or if you  */
/*  don't have vertex data structures at all), set `vertexpool' to NULL.     */
/*  This will cause all link data structures to be allocated from a common   */
/*  pool, thereby sacrificing some of the memory locality and compression    */
/*  of the data structure.  It will also disable the macros (as they will    */
/*  dereference a NULL pointer).                                             */
/*                                                                           */
/*  Don't call this procedure on a tetcomplex that has already been          */
/*  initialized (by this procedure), unless you call tetcomplexdeinit() on   */
/*  it first.  You will leak memory.  Also see tetcomplexrestart().          */
/*                                                                           */
/*  plex:  The tetcomplex to initialize.                                     */
/*  vertexpool:  The proxipool of vertices associated with this tetcomplex.  */
/*    The tags stored in the tetcomplex reference these vertices.  This      */
/*    parameter may be set to NULL, but if it is, you cannot subsequently    */
/*    use tetcomplextag2vertex() or tetcomplextag2attributes().              */
/*  verbose:  How much debugging information tetcomplex procedures should    */
/*    print, from none (0) to lots (4+).                                     */
/*                                                                           */
/*****************************************************************************/

void tetcomplexinit(struct tetcomplex *plex,
                    struct proxipool *vertexpool,
                    int verbose)
{
  /* Initialize a pool to store the molecules in the 1D and 2D links. */
  proxipoolinit(&plex->moleculepool, MOLECULESIZE, 0, verbose);
  /* Initialize a cache for fast 2D link lookups. */
  link2dcacheinit(plex->cache);
  /* Initialize a pool to store the 3D stars. */
  arraypoolinit(&plex->stars, sizeof(struct tetcomplexstar), 10, 0);
  /* Remember the vertices in the tetcomplex. */
  plex->vertexpool = vertexpool;
  /* No tag has a star yet. */
  plex->nextinitindex = 0;
  /* No tetrahedra yet. */
  plex->tetcount = 0;
  plex->ghosttetcount = 0;
  plex->consistentflag = 1;
  plex->verbosity = verbose;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexrestart()   Empty a tetrahedral complex.                       */
/*                                                                           */
/*  The complex is returned to its starting state, except that no memory is  */
/*  freed to the operating system.  Rather, the previously allocated         */
/*  proxipool (of molecules) and arraypool (of stars) are ready to be        */
/*  reused.                                                                  */
/*                                                                           */
/*  plex:  The tetcomplex to restart.                                        */
/*                                                                           */
/*****************************************************************************/

void tetcomplexrestart(struct tetcomplex *plex)
{
  /* Restart the memory pools. */
  proxipoolrestart(&plex->moleculepool);
  arraypoolrestart(&plex->stars);
  /* Empty the cache for fast 2D link lookups. */
  link2dcacheinit(plex->cache);
  /* No tag has a star yet. */
  plex->nextinitindex = 0;
  /* No tetrahedra yet. */
  plex->tetcount = 0;
  plex->ghosttetcount = 0;
  plex->consistentflag = 1;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexdeinit()   Free to the operating system all memory taken by a  */
/*                       tetcomplex.                                         */
/*                                                                           */
/*  plex:  The tetcomplex to free.                                           */
/*                                                                           */
/*****************************************************************************/

void tetcomplexdeinit(struct tetcomplex *plex)
{
  proxipooldeinit(&plex->moleculepool);
  arraypooldeinit(&plex->stars);
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplextag2vertex()   Map a tag to the vertex it indexes.             */
/*                                                                           */
/*  This procedure is much like proxipooltag2object(), but it saves callers  */
/*  from needing to remember which proxipool holds the vertices associated   */
/*  with a tetrahedral complex (and possibly getting it wrong).              */
/*                                                                           */
/*  WARNING:  fails catastrophically, probably with a segmentation fault, if */
/*  the tag's minipool doesn't yet exist.                                    */
/*                                                                           */
/*  Implemented as a macro to meet your need for speed.                      */
/*                                                                           */
/*  plex:  The tetcomplex in which to find a vertex.                         */
/*         Type (struct tetcomplex *).                                       */
/*  searchtag:  The tag whose vertex is sought.                              */
/*              Type (tag).                                                  */
/*                                                                           */
/*  Returns a pointer to the vertex.  Might crash if the tag has not been    */
/*    allocated yet.                                                         */
/*    Type (void *).                                                         */
/*                                                                           */
/*****************************************************************************/

#define tetcomplextag2vertex(plex, searchtag)  \
  proxipooltag2object(plex->vertexpool, searchtag)

/*****************************************************************************/
/*                                                                           */
/*  tetcomplextag2attributes()   Map a tag to the vertex attributes (stored  */
/*                               in a supplementary object) it indexes.      */
/*                                                                           */
/*  This procedure is much like proxipooltag2object2(), but it saves callers */
/*  from needing to remember which proxipool holds the vertices associated   */
/*  with a tetrahedral complex (and possibly getting it wrong).              */
/*                                                                           */
/*  WARNING:  fails catastrophically, probably with a segmentation fault, if */
/*  the tag's minipool doesn't yet exist.                                    */
/*                                                                           */
/*  Implemented as a macro to meet your need for speed.                      */
/*                                                                           */
/*  plex:  The tetcomplex in which to find a vertex's attributes.            */
/*         Type (struct tetcomplex *).                                       */
/*  searchtag:  The tag whose attributes (supplementary object) are sought.  */
/*              Type (tag).                                                  */
/*                                                                           */
/*  Returns a pointer to the vertex attributes.  Might crash if the tag has  */
/*    not been allocated yet.                                                */
/*    Type (void *).                                                         */
/*                                                                           */
/*****************************************************************************/

#define tetcomplextag2attributes(plex, searchtag)  \
  proxipooltag2object2(plex->vertexpool, searchtag)

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexringadjacencies()   Search the link of a specified edge for    */
/*                                the apex vertices of the two tetrahedra    */
/*                                having a specified triangle for a face.    */
/*                                                                           */
/*  This procedure is a helper procedure for tetcomplexadjacencies().  It    */
/*  searches for the tetrahedra adjoining triangle (vtx1, vtx2, vtx3), but   */
/*  it only looks in the star of the (undirected) edge (vtx1, vtx2), which   */
/*  is appropriate if `vtx1' and `vtx2' have the same parity.                */
/*                                                                           */
/*  Do not use this procedure if the stars of `vtx1' and `vtx2' might be     */
/*  inconsistent with each other and disagree about the star/link of the     */
/*  edge (vtx1, vtx2).                                                       */
/*                                                                           */
/*  plex:  The tetcomplex that contains the triangle.                        */
/*  vtx1, vtx2, vtx3:  The vertices of the query triangle.  (vtx1, vtx2) is  */
/*    the (only) edge whose link ring will be searched.                      */
/*  adjacencies[2]:  Array in which the procedure returns the tags of the    */
/*    apex vertices of the two tetrahedra adjoining the query triangle.      */
/*    The tetrahedra have orientations (vtx1, vtx2, vtx3, adjacencies[1])    */
/*    and (vtx1, vtx2, adjacencies[0], vtx3).  One or both elements of this  */
/*    arrary may be GHOSTVERTEX, if there are no such adjoining tetrahedra.  */
/*    The contents of this array do not need to be initialized prior to      */
/*    calling this procedure.                                                */
/*                                                                           */
/*  Returns 1 if the triangle is in the tetcomplex; 0 otherwise.             */
/*                                                                           */
/*****************************************************************************/

int tetcomplexringadjacencies(struct tetcomplex *plex,
                              tag vtx1,
                              tag vtx2,
                              tag vtx3,
                              tag adjacencies[2])
{
  struct tetcomplexstar *star;
  tag ring;
  tag swap;

  /* The link ring for the edge (vtx1, vtx2) is stored in the star for one   */
  /*   of those two vertices.  If one of the vertices is GHOSTVERTEX, it is  */
  /*   stored with the other vertex (GHOSTVERTEX never stores its star).     */
  /*   Otherwise, if both vertices have the same two's bit, the edge's link  */
  /*   ring is stored in the star of the vertex with the greater index.  If  */
  /*   the vertices have opposite two's bits, the edge's link is stored with */
  /*   the vertex with the lesser index.  See the tetcomplex header for an   */
  /*   explanation.                                                          */
  if ((vtx2 == GHOSTVERTEX) ||
      ((vtx1 != GHOSTVERTEX) &&
       ((vtx1 < vtx2) ^ ((vtx1 & 2) == (vtx2 & 2))))) {
    /* Does vertex `vtx1' even have a star yet? */
    if (vtx1 >= plex->nextinitindex) {
      /* No. */
      adjacencies[0] = STOP;
      adjacencies[1] = STOP;
      return 0;
    }
    /* Look up the star of `vtx1'. */
    star = (struct tetcomplexstar *)
           arraypoolfastlookup(&plex->stars, (arraypoolulong) vtx1);
    /* Search it for the link ring of (vtx1, vtx2). */
    ring = link2dfindring(&plex->moleculepool, plex->cache, star->linkhead,
                          vtx1, vtx2);
    /* Find the neighbors of `vtx3' in the link ring.  Note that if the edge */
    /*   (vtx1, vtx2) is not present, `ring' is STOP, but the following line */
    /*   will do the right thing (return 0) anyway.                          */
    return linkringadjacencies(&plex->moleculepool, ring, vtx1, vtx3,
                               adjacencies);
  } else {
    /* Does vertex `vtx2' even have a star yet? */
    if (vtx2 >= plex->nextinitindex) {
      /* No. */
      adjacencies[0] = STOP;
      adjacencies[1] = STOP;
      return 0;
    }
    /* Look up the star of `vtx2'. */
    star = (struct tetcomplexstar *)
           arraypoolfastlookup(&plex->stars, (arraypoolulong) vtx2);
    /* Search it for the link ring of (vtx2, vtx1). */
    ring = link2dfindring(&plex->moleculepool, plex->cache, star->linkhead,
                          vtx2, vtx1);
    /* Find the neighbors of `vtx3' in the link ring. */
    if (linkringadjacencies(&plex->moleculepool, ring, vtx2, vtx3,
                            adjacencies)) {
      /* The orientation of the edge and the link ring is opposite to the */
      /*   orientation of the query, so swap the tetrahedron apices to    */
      /*   compensate.                                                    */
      swap = adjacencies[0];
      adjacencies[0] = adjacencies[1];
      adjacencies[1] = swap;
      return 1;
    }
    return 0;
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexadjacencies()   Find the apex vertices of the two tetrahedra   */
/*                            having a specified triangle for a face.  Known */
/*                            as a "triangle query" for short.               */
/*                                                                           */
/*  This procedure only works correctly if all the vertex and edge stars     */
/*  (i.e. link2d and linkring data structures) in the tetcomplex are         */
/*  consistent with each other.                                              */
/*                                                                           */
/*  plex:  The tetcomplex that contains the triangle.                        */
/*  vtx1, vtx2, vtx3:  The vertices of the query triangle.                   */
/*  adjacencies[2]:  Array in which the procedure returns the tags of the    */
/*    apex vertices of the two tetrahedra adjoining the query triangle.      */
/*    The tetrahedra have orientations (vtx1, vtx2, vtx3, adjacencies[1])    */
/*    and (vtx1, vtx2, adjacencies[0], vtx3).  One or both elements of this  */
/*    array may be GHOSTVERTEX, if there are no such adjoining tetrahedra.   */
/*    The contents of this array do not need to be initialized prior to      */
/*    calling this procedure.                                                */
/*                                                                           */
/*  Returns 1 if the triangle is in the tetcomplex; 0 otherwise.             */
/*                                                                           */
/*****************************************************************************/

int tetcomplexadjacencies(struct tetcomplex *plex,
                          tag vtx1,
                          tag vtx2,
                          tag vtx3,
                          tag adjacencies[2])
{
  /* Reject a query triangle with two identical vertices. */
  if ((vtx1 == vtx2) || (vtx2 == vtx3) || (vtx3 == vtx1)) {
    return 0;
  }

  /* Do `vtx1' and `vtx2' have the same parity? */
  if ((vtx1 & 1) == (vtx2 & 1)) {
    /* Yes; check the link ring of edge (vtx1, vtx2). */
    return tetcomplexringadjacencies(plex, vtx1, vtx2, vtx3, adjacencies);
  } else if ((vtx2 & 1) == (vtx3 & 1)) {
    /* Check the link ring of edge (vtx2, vtx3). */
    return tetcomplexringadjacencies(plex, vtx2, vtx3, vtx1, adjacencies);
  } else {
    /* `vtx3' and `vtx1' must have the same parity. */
    return tetcomplexringadjacencies(plex, vtx3, vtx1, vtx2, adjacencies);
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexedge2tet()   Find one tetrahedron adjoining a specified edge.  */
/*                         Known as an "edge query" for short.               */
/*                                                                           */
/*  Never returns a ghost tetrahedron.  If there is no solid tetrahedron     */
/*  adjoining the query vertex, this procedure returns 0, and all four       */
/*  entries of adjtet are set to STOP.                                       */
/*                                                                           */
/*  This procedure only works correctly if all the vertex and edge stars     */
/*  (i.e. link2d and linkring data structures) in the tetcomplex are         */
/*  consistent with each other.                                              */
/*                                                                           */
/*  plex:  The tetcomplex that contains the edge.                            */
/*  vtx1, vtx2:  The vertices of the query edge.                             */
/*  adjtet[4]:  Array in which the procedure returns the tags of the         */
/*    vertices of a tetrahedron adjoining the query vertex.  If there is no  */
/*    such tetrahedron, all four vertices will be GHOSTVERTEX.  The contents */
/*    of this array do not need to be initialized prior to calling this      */
/*    procedure.                                                             */
/*                                                                           */
/*  Returns 1 if the tetcomplex contains a solid tetrahedron that has the    */
/*  query edge; 0 otherwise.                                                 */
/*                                                                           */
/*****************************************************************************/

int tetcomplexedge2tet(struct tetcomplex *plex,
                       tag vtx1,
                       tag vtx2,
                       tag adjtet[4])
{
  struct link2dposition pos2d;
  struct linkposition pos1d;
  struct tetcomplexstar *star;
  tag vertexandlink[2];
  tag endpt1, endpt2, firstendpt;
  tag vtxloop;

  /* If a tetrahedron is found, it will be returned with the query vertices */
  /*   listed first.                                                        */
  adjtet[0] = vtx1;
  adjtet[1] = vtx2;

  /* Loop through the stars of all the vertices, searching for a tetrahedron */
  /*   with edge (vtx1, vtx2).  Search the star of `vtx1' first, then the    */
  /*   star of `vtx2', then all the other stars starting from the star after */
  /*   `vtx2' (wrapping around from the highest numbered star to zero).      */
  vtxloop = STOP;
  while (1) {
    /* The following code advances `vtxloop' to the next star.  Because   */
    /*   `vtx1' and `vtx2' might not have been allocated stars, a loop is */
    /*   needed here to skip indices that haven't been allocated yet.     */
    do {
      if (vtxloop == STOP) {
        /* Search the star of `vtx1' first. */
        vtxloop = vtx1;
      } else if (vtxloop == vtx1) {
        /* Search the star of `vtx2' second. */
        vtxloop = vtx2;
      } else {
        /* Advance to the next star, wrapping around if necessary. */
        if (vtxloop >= plex->nextinitindex) {
          vtxloop = 0;
        } else {
          vtxloop++;
        }
        /* If we reach `vtx1', advance again so we don't do `vtx1' twice. */
        if (vtxloop == vtx1) {
          vtxloop++;
        }
        /* If we reach `vtx2', we've gone through the whole list. */
        if ((vtxloop == vtx2) ||
            ((vtxloop >= plex->nextinitindex) &&
             (vtx2 >= plex->nextinitindex))) {
          /* No tetrahedron adjoins (vtx1, vtx2). */
          adjtet[0] = STOP;
          adjtet[1] = STOP;
          adjtet[2] = STOP;
          adjtet[3] = STOP;
          return 0;
        }
      }
      /* If `vtxloop' is not an allocated index, loop. */
    } while (vtxloop >= plex->nextinitindex);

    /* Look up the star of `vtxloop'. */
    star = (struct tetcomplexstar *)
           arraypoolfastlookup(&plex->stars, (arraypoolulong) vtxloop);

    /* Loop through the vertices in the 2D link of vertex `vtxloop'.  Skip  */
    /*   ghost vertices.  We could search every link ring in the whole      */
    /*   tetcomplex, but that's unnecessarily slow.  If there exists a      */
    /*   tetrahedron with edge (vtx1, vtx2), at least one of the two        */
    /*   vertices has the same parity as some other vertex of the           */
    /*   tetrahedron.  Therefore, if we only look at the link rings of the  */
    /*   edges that adjoin at least one of `vtx1' or `vtx2', we'll find the */
    /*   tetrahedron.                                                       */
    link2diteratorinit(&plex->moleculepool, star->linkhead, vtxloop, &pos2d);
    link2diterate(&pos2d, vertexandlink);
    while (vertexandlink[0] != STOP) {
      /* Skip ghost vertices and edges not adjoining `vtx1' nor `vtx2'. */
      if ((vertexandlink[0] != GHOSTVERTEX) &&
          ((vtxloop == vtx1) || (vtxloop == vtx2) ||
           (vertexandlink[0] == vtx1) || (vertexandlink[0] == vtx2))) {
        /* Find the first tetrahedron in the star of edge */
        /*   (vtxloop, vertexandlink[0]).                 */
        linkringiteratorinit(&plex->moleculepool, vertexandlink[1], vtxloop,
                             &pos1d);
        endpt1 = linkringiterate(&pos1d);
        endpt2 = linkringiterate(&pos1d);
        /* `endpt1' comes around again at the end of the ring, if it's not */
        /*   a ghost vertex.                                               */
        firstendpt = (endpt1 == GHOSTVERTEX) ? STOP : endpt1;

        /* Loop through the tetrahedra in the star of edge */
        /*   (vtxloop, vertexandlink[0]).                  */
        do {
          /* If this is a ghost tetrahedron, don't check for the edge. */
          if ((endpt1 != GHOSTVERTEX) && (endpt2 != GHOSTVERTEX)) {
            /* Not a ghost tetrahedron.  Check for the edge (vtx1, vtx2). */
            if (vtxloop == vtx1) {
              if (vertexandlink[0] == vtx2) {
                adjtet[2] = endpt1;
                adjtet[3] = endpt2;
                return 1;
              } else if (endpt1 == vtx2) {
                adjtet[2] = endpt2;
                adjtet[3] = vertexandlink[0];
                return 1;
              } else if (endpt2 == vtx2) {
                adjtet[2] = vertexandlink[0];
                adjtet[3] = endpt1;
                return 1;
              }
            } else if (vtxloop == vtx2) {
              if (vertexandlink[0] == vtx1) {
                adjtet[2] = endpt2;
                adjtet[3] = endpt1;
                return 1;
              } else if (endpt1 == vtx1) {
                adjtet[2] = vertexandlink[0];
                adjtet[3] = endpt2;
                return 1;
              } else if (endpt2 == vtx1) {
                adjtet[2] = endpt1;
                adjtet[3] = vertexandlink[0];
                return 1;
              }
            } else if (vertexandlink[0] == vtx1) {
              if (endpt1 == vtx2) {
                adjtet[2] = vtxloop;
                adjtet[3] = endpt2;
                return 1;
              } else if (endpt2 == vtx2) {
                adjtet[2] = endpt1;
                adjtet[3] = vtxloop;
                return 1;
              }
            } else if (vertexandlink[0] == vtx2) {
              if (endpt1 == vtx1) {
                adjtet[2] = endpt2;
                adjtet[3] = vtxloop;
                return 1;
              } else if (endpt2 == vtx1) {
                adjtet[2] = vtxloop;
                adjtet[3] = endpt1;
                return 1;
              }
            }
          }

          /* Iterate over the next tetrahedron in the star. */
          if (endpt2 == firstendpt) {
            /* We've wrapped around the end of the link ring, so we're done. */
            endpt2 = STOP;
          } else {
            endpt1 = endpt2;
            endpt2 = linkringiterate(&pos1d);
            /* If we've reached the end of the link ring, and the first      */
            /*   vertex in the ring was not a ghost vertex, consider the     */
            /*   tetrahedron having the first and last vertices in the ring. */
            if (endpt2 == STOP) {
              endpt2 = firstendpt;
            }
          }
        } while (endpt2 != STOP);
      }

      /* Iterate over the next vertex in the star of vertex `vtxloop'. */
      link2diterate(&pos2d, vertexandlink);
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexvertex2tet()   Find one tetrahedron adjoining a specified      */
/*                           vertex.  Known as a "vertex query" for short.   */
/*                                                                           */
/*  Never returns a ghost tetrahedron.  If there is no solid tetrahedron     */
/*  adjoining the query vertex, this procedure returns 0, and all four       */
/*  entries of adjtet are set to STOP.                                       */
/*                                                                           */
/*  plex:  The tetcomplex that contains the vertex.                          */
/*  vtx:  The query vertex.                                                  */
/*  adjtet[4]:  Array in which the procedure returns the tags of the         */
/*    vertices of a tetrahedron adjoining the query vertex.  If there is no  */
/*    such tetrahedron, all four vertices will be GHOSTVERTEX.  The contents */
/*    of this array do not need to be initialized prior to calling this      */
/*    procedure.                                                             */
/*                                                                           */
/*  Returns 1 if the tetcomplex contains a solid tetrahedron that adjoins    */
/*  the query vertex; 0 otherwise.                                           */
/*                                                                           */
/*****************************************************************************/

int tetcomplexvertex2tet(struct tetcomplex *plex,
                         tag vtx,
                         tag adjtet[4])
{
  struct link2dposition pos2d;
  struct linkposition pos1d;
  struct tetcomplexstar *star;
  tag vertexandlink[2];
  tag endpt1, endpt2, firstendpt;
  tag vtxloop;

  /* If a tetrahedron is found, it will be returned with the query vertex */
  /*   listed first.                                                      */
  adjtet[0] = vtx;

  /* Does vertex `vtx' even have a star yet? */
  if (vtx < plex->nextinitindex) {
    /* Maybe.  Start by searching its star. */
    vtxloop = vtx;
  } else {
    /* No.  Start searching the star of vertex 0. */
    vtxloop = 0;
  }

  /* Loop through the stars of all the vertices, searching for a tetrahedron */
  /*   adjoining vertex `vtx'.                                               */
  while (1) {
    /* Look up the star of `vtxloop'. */
    star = (struct tetcomplexstar *)
           arraypoolfastlookup(&plex->stars, (arraypoolulong) vtxloop);
    /* Loop through the vertices in the 2D link of vertex `vtxloop'. */
    link2diteratorinit(&plex->moleculepool, star->linkhead, vtxloop, &pos2d);
    link2diterate(&pos2d, vertexandlink);
    while (vertexandlink[0] != STOP) {
      /* Skip ghost vertices. */
      if (vertexandlink[0] != GHOSTVERTEX) {
        /* Find the first tetrahedron in the star of edge */
        /*   (vtxloop, vertexandlink[0]).                 */
        linkringiteratorinit(&plex->moleculepool, vertexandlink[1], vtxloop,
                             &pos1d);
        endpt1 = linkringiterate(&pos1d);
        endpt2 = linkringiterate(&pos1d);
        /* `endpt1' comes around again at the end of the ring, if it's not */
        /*   a ghost vertex.                                               */
        firstendpt = (endpt1 == GHOSTVERTEX) ? STOP : endpt1;

        /* Loop through the tetrahedra in the star of vertex `vtxloop'. */
        do {
          /* If this is a ghost tetrahedron, don't check for the vertex. */
          if ((endpt1 != GHOSTVERTEX) && (endpt2 != GHOSTVERTEX)) {
            /* Not a ghost tetrahedron.  Check for vertex `vtx'. */
            if (vtxloop == vtx) {
              adjtet[1] = vertexandlink[0];
              adjtet[2] = endpt1;
              adjtet[3] = endpt2;
              return 1;
            } else if (vertexandlink[0] == vtx) {
              adjtet[1] = vtxloop;
              adjtet[2] = endpt2;
              adjtet[3] = endpt1;
              return 1;
            } else if (endpt1 == vtx) {
              adjtet[1] = endpt2;
              adjtet[2] = vtxloop;
              adjtet[3] = vertexandlink[0];
              return 1;
            } else if (endpt2 == vtx) {
              adjtet[1] = endpt1;
              adjtet[2] = vertexandlink[0];
              adjtet[3] = vtxloop;
              return 1;
            }
          }

          /* Iterate over the next tetrahedron in the star. */
          if (endpt2 == firstendpt) {
            /* We've wrapped around the end of the link ring, so we're done. */
            endpt2 = STOP;
          } else {
            endpt1 = endpt2;
            endpt2 = linkringiterate(&pos1d);
            /* If we've reached the end of the link ring, and the first      */
            /*   vertex in the ring was not a ghost vertex, consider the     */
            /*   tetrahedron having the first and last vertices in the ring. */
            if (endpt2 == STOP) {
              endpt2 = firstendpt;
            }
          }
        } while (endpt2 != STOP);
      }

      /* Iterate over the next vertex in the star of vertex `vtxloop'. */
      link2diterate(&pos2d, vertexandlink);
    }

    /* Iterate over the next vertex star. */
    vtxloop++;
    /* If we reach `vtx', we've gone through the whole list. */
    if ((vtxloop == vtx) ||
        ((vtxloop >= plex->nextinitindex) && (vtx >= plex->nextinitindex))) {
      /* No tetrahedron adjoins `vtx'. */
      adjtet[0] = STOP;
      adjtet[1] = STOP;
      adjtet[2] = STOP;
      adjtet[3] = STOP;
      return 0;
    }
    if (vtxloop >= plex->nextinitindex) {
      /* Wrap around to the star of vertex 0. */
      vtxloop = 0;
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexiteratorinit()   Initialize an iterator that traverses all the */
/*                             tetrahedra in a tetcomplex one by one.        */
/*                                                                           */
/*  The iterator is a variable `pos', whose internals should not be          */
/*  examined or modified by the client.  The iterator's job is to keep       */
/*  track of where it is in the lists of tetrahedra.  This procedure sets    */
/*  the iterator so that the first call to tetcomplexiterateall() will find  */
/*  the first tetrahedron in the first link ring in the first nonempty       */
/*  link2d.                                                                  */
/*                                                                           */
/*  When a tetcomplex is modified, any iterators on that tetcomplex may be   */
/*  corrupted and should not be used without being initialized (by this      */
/*  procedure) again.                                                        */
/*                                                                           */
/*  plex:  The tetcomplex whose tetrahedra you want to iterate over.         */
/*  pos:  The iterator.  Its contents do not need to be initialized prior to */
/*    calling this procedure.                                                */
/*                                                                           */
/*****************************************************************************/

void tetcomplexiteratorinit(struct tetcomplex *plex,
                            struct tetcomplexposition *pos)
{
  pos->mycomplex = plex;
  /* Start with the star of the vertex having tag zero. */
  pos->starvertex = 0;
  /* The iterator is not in the middle of a link. */
  pos->link2dvertex = STOP;
  pos->link1dprevvertex = STOP;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexiterateall()   Advance a tetcomplexposition iterator to the    */
/*                           next tetrahedron and return it (with            */
/*                           duplicates).                                    */
/*                                                                           */
/*  This procedure returns every _copy_ of every tetrahedron in the data     */
/*  structure, so it exposes the underlying implementation, and the fact     */
/*  that each solid tetrahedron is stored in the link rings of two, three,   */
/*  or six edges (depending on the parities of the tetrahedron's vertices).  */
/*  In most cases, it's better to use tetcomplexiterate() or                 */
/*  tetcomplexiteratenoghosts() instead of this procedure, because they      */
/*  return each tetrahedron only once.  (They call this procedure and filter */
/*  out duplicate tetrahedra.)                                               */
/*                                                                           */
/*  However, when the stars are not consistent with each other (as in the    */
/*  star splaying algorithm), this procedure can be useful because it        */
/*  returns "ordered" tetrahedra.  Each tetrahedron returned is in the star  */
/*  of the vertex nexttet[0], and in the star of the edge (nexttet[0],       */
/*  nexttet[1]).                                                             */
/*                                                                           */
/*  This procedure also returns ghost tetrahedra.  Even if no ghost          */
/*  tetrahedron has been explicitly inserted into the complex, there will    */
/*  still be ghost tetrahedra returned for triangles that are faces of       */
/*  exactly one solid tetrahedron.  If ghost tetrahedra have been inserted,  */
/*  more copies of them will be returned.  Any vertex of the returned        */
/*  tetrahedron can be GHOSTVERTEX except the first one (nexttet[0]).        */
/*                                                                           */
/*  The iterator is a variable `pos', whose internals should not be          */
/*  examined or modified by the client.                                      */
/*                                                                           */
/*  When a tetcomplex is modified, any iterators on that tetcomplex may be   */
/*  corrupted and should not be passed to this procedure again until they    */
/*  are re-initialized.                                                      */
/*                                                                           */
/*  pos:  The iterator.                                                      */
/*  nexttet:  An array used to return the tags for the vertices of the       */
/*    next tetrahedron.  The tetrahedron is always returned with positive    */
/*    orientation.  If the iterator has enumerated all the tetrahedra in the */
/*    complex, all four vertices will be STOP on return.  Does not need to   */
/*    be initialized before the call.                                        */
/*                                                                           */
/*****************************************************************************/

void tetcomplexiterateall(struct tetcomplexposition *pos,
                          tag nexttet[4])
{
  struct tetcomplexstar *star;
  tag vertexandlink[2];
  int iteratorflag;

  if (pos->link1dprevvertex != STOP) {
    /* We're in the middle of traversing a link ring, so find the next edge */
    /*   in the ring.                                                       */
    nexttet[0] = pos->starvertex;
    nexttet[1] = pos->link2dvertex;
    /* The previous vertex is one endpoint of the edge. */
    nexttet[2] = pos->link1dprevvertex;
    /* The next vertex in the link ring is the other endpoint. */
    nexttet[3] = linkringiterate(&pos->link1dposition);
    pos->link1dprevvertex = nexttet[3];
    if (nexttet[3] == STOP) {
      /* We've reach the end of the list, so "close" the link ring by using */
      /*   the first vertex in the list as the last endpoint.               */
      nexttet[3] = pos->link1dfirstvertex;
    }
    return;
  }

  /* We need to find the next link ring to traverse.  Are there any vertex */
  /*   stars left to traverse?                                             */
  while (pos->starvertex < pos->mycomplex->nextinitindex) {
    /* Presume we'll find a vertex's 2D link until proven otherwise. */
    iteratorflag = 1;
    /* Are we in the middle of traversing a vertex's 2D link? */
    if (pos->link2dvertex == STOP) {
      /* No.  Find the next vertex star to traverse. */
      star = (struct tetcomplexstar *)
             arraypoolfastlookup(&pos->mycomplex->stars,
                                 (arraypoolulong) pos->starvertex);
      if (star->linkhead == STOP) {
        /* Vertex `pos->starvertex' doesn't have a star.  Try the */
        /*   next vertex.                                         */
        iteratorflag = 0;
        pos->starvertex++;
      } else {
        /* Prepare to iterate through the vertex's 2D link. */
        link2diteratorinit(&pos->mycomplex->moleculepool, star->linkhead,
                           pos->starvertex, &pos->link2dposition);
      }
    }

    /* Are we traversing a 2D link? */
    if (iteratorflag) {
      /* Yes.  Find the next vertex and link ring in the 2D link. */
      link2diterate(&pos->link2dposition, vertexandlink);
      pos->link2dvertex = vertexandlink[0];
      /* Have we reached the end of the list? */
      if (vertexandlink[0] != STOP) {
        /* No.  Return a tetrahedron adjoining this edge. */
        nexttet[0] = pos->starvertex;
        nexttet[1] = vertexandlink[0];
        /* Find the first edge in the new link ring. */
        linkringiteratorinit(&pos->mycomplex->moleculepool, vertexandlink[1],
                             pos->starvertex, &pos->link1dposition);
        nexttet[2] = linkringiterate(&pos->link1dposition);
        pos->link1dfirstvertex = nexttet[2];
        nexttet[3] = linkringiterate(&pos->link1dposition);
        pos->link1dprevvertex = nexttet[3];
        return;
      }
      pos->starvertex++;
    }
  }

  /* There are no more vertex stars to traverse or tetrahedra to return. */
  nexttet[0] = STOP;
  nexttet[1] = STOP;
  nexttet[2] = STOP;
  nexttet[3] = STOP;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexiterate()   Advance a tetcomplexposition iterator to a new     */
/*                        tetrahedron and return it (skipping duplicates).   */
/*                                                                           */
/*  This procedure returns every tetrahedron in the data structure once.     */
/*  It returns ghost tetrahedra as well as solid tetrahedra (even if no      */
/*  ghost tetrahedron has been explicitly inserted into the complex):  for   */
/*  each triangle that is a face of exactly one solid tetrahedron, a ghost   */
/*  tetrahedron adjoining that face is returned.                             */
/*                                                                           */
/*  Ghost tetrahedra explicitly inserted into the tetcomplex have no effect  */
/*  on the tetrahedra this procedure returns!  The ghost tetrahedra returned */
/*  depend solely on the solid tetrahedra.  (You will notice this only if    */
/*  the inserted ghost tetrahedra are inconsistent with the solid            */
/*  tetrahedra.)                                                             */
/*                                                                           */
/*  The first two vertices (nexttet[0] and nexttet[1]) of the returned       */
/*  tetrahedron are never GHOSTVERTEX.  A ghost tetrahedron has its ghost    */
/*  vertex in one of the last two places (nexttet[2] or nexttet[3]).         */
/*                                                                           */
/*  The iterator is a variable `pos', whose internals should not be          */
/*  examined or modified by the client.                                      */
/*                                                                           */
/*  When a tetcomplex is modified, any iterators on that tetcomplex may be   */
/*  corrupted and should not be passed to this procedure again until they    */
/*  are re-initialized.                                                      */
/*                                                                           */
/*  pos:  The iterator.                                                      */
/*  nexttet:  An array used to return the tags for the vertices of the       */
/*    next tetrahedron.  The tetrahedron is always returned with positive    */
/*    orientation.  If the iterator has enumerated all the tetrahedra in the */
/*    complex, all four vertices will be STOP on return.  Does not need to   */
/*    be initialized before the call.                                        */
/*                                                                           */
/*****************************************************************************/

void tetcomplexiterate(struct tetcomplexposition *pos,
                       tag nexttet[4])
{
  /* To ensure that no tetrahedron is returned twice (with the vertices in   */
  /*   a different order, we use the following rules.  (It's helpful to      */
  /*   remember that nexttet[0] and nexttet[1] always have the same parity.) */
  /*                                                                         */
  /* (1)  Do not return the tetrahedron if nexttet[1] is GHOSTVERTEX.  This  */
  /*      ensures that no tetrahedron in the star of a ghost edge is ever    */
  /*      returned; so ghost tetrahedra explicitly inserted into the         */
  /*      tetcomplex have no effect on the tetrahedra this procedure         */
  /*      returns.                                                           */
  /* (2)  Do not return the tetrahedron if nexttet[2] has the same parity as */
  /*      nexttet[0] and nexttet[1], and a smaller index than at least one   */
  /*      of those two.  (The tetrahedron is in at least three link rings,   */
  /*      one for each of the edges of the triangle nexttet[0, 1, 2], so     */
  /*      return it only when nexttet[2] has the largest index.)             */
  /* (3)  Same thing for nexttet[3] (replacing nexttet[2]).                  */
  /* (4)  Do not return the tetrahedron if nexttet[2] has the same parity as */
  /*      nexttet[3], and either nexttet[0] or nexttet[1] has the largest    */
  /*      index of all four tetrahedron vertices.  (The tetrahedron is in    */
  /*      the link rings of two edges, nexttet[0, 1] and nexttet[2, 3], and  */
  /*      the edge containing the vertex with the largest index defers to    */
  /*      the other edge.)                                                   */
  /*                                                                         */
  /* These rules ensure that only one copy of each tetrahedron is returned.  */
  do {
    tetcomplexiterateall(pos, nexttet);
  } while ((nexttet[1] == GHOSTVERTEX) ||
           (((nexttet[2] & 1) == (nexttet[0] & 1)) &&
            ((nexttet[2] < nexttet[0]) || (nexttet[2] < nexttet[1]))) ||
           (((nexttet[3] & 1) == (nexttet[0] & 1)) &&
            ((nexttet[3] < nexttet[0]) || (nexttet[3] < nexttet[1]))) ||
           (((nexttet[3] & 1) == (nexttet[2] & 1)) &&
            (((nexttet[2] < nexttet[0]) && (nexttet[3] < nexttet[0])) ||
             ((nexttet[2] < nexttet[1]) && (nexttet[3] < nexttet[1])))));
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexiteratenoghosts()   Advance a tetcomplexposition iterator to a */
/*                                new solid tetrahedron and return it        */
/*                                (skipping duplicates).                     */
/*                                                                           */
/*  This procedure returns every solid tetrahedron in the data structure     */
/*  once.  Ghost tetrahedra are skipped.                                     */
/*                                                                           */
/*  The iterator is a variable `pos', whose internals should not be          */
/*  examined or modified by the client.                                      */
/*                                                                           */
/*  When a tetcomplex is modified, any iterators on that tetcomplex may be   */
/*  corrupted and should not be passed to this procedure again until they    */
/*  are re-initialized.                                                      */
/*                                                                           */
/*  pos:  The iterator.                                                      */
/*  nexttet:  An array used to return the tags for the vertices of the       */
/*    next tetrahedron.  The tetrahedron is always returned with positive    */
/*    orientation.  If the iterator has enumerated all the tetrahedra in the */
/*    complex, all four vertices will be STOP on return.  Does not need to   */
/*    be initialized before the call.                                        */
/*                                                                           */
/*****************************************************************************/

void tetcomplexiteratenoghosts(struct tetcomplexposition *pos,
                               tag nexttet[4])
{
  /* This loop ensures that no ghost tetrahedron is returned (note that   */
  /*   nexttet[0] is never a GHOSTVERTEX), and no tetrahedron is returned */
  /*   twice.  For an explanation of how the latter is accomplished, see  */
  /*   the comments in tetcomplexiterate().  The first copy of each       */
  /*   tetrahedron is returned, and later copies are not.                 */
  do {
    tetcomplexiterateall(pos, nexttet);
  } while ((nexttet[1] == GHOSTVERTEX) || (nexttet[2] == GHOSTVERTEX) ||
           (nexttet[3] == GHOSTVERTEX) ||
           (((nexttet[2] & 1) == (nexttet[0] & 1)) &&
            ((nexttet[2] < nexttet[0]) || (nexttet[2] < nexttet[1]))) ||
           (((nexttet[3] & 1) == (nexttet[0] & 1)) &&
            ((nexttet[3] < nexttet[0]) || (nexttet[3] < nexttet[1]))) ||
           (((nexttet[3] & 1) == (nexttet[2] & 1)) &&
            (((nexttet[2] < nexttet[0]) && (nexttet[3] < nexttet[0])) ||
             ((nexttet[2] < nexttet[1]) && (nexttet[3] < nexttet[1])))));
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexprint()   Print the contents of a tetcomplex.                  */
/*                                                                           */
/*  This procedure prints every tetrahedron in a tetcomplex.  It only works  */
/*  correctly if the stars are consistent with each other; for instance, it  */
/*  will not print meaningful information half way through star splaying.    */
/*                                                                           */
/*  plex:  The tetcomplex to print.                                          */
/*                                                                           */
/*****************************************************************************/

void tetcomplexprint(struct tetcomplex *plex) {
  struct tetcomplexposition pos;
  tag nexttet[4];
  int i;

  printf("List of all tetrahedra in the tetcomplex:\n");
  tetcomplexiteratorinit(plex, &pos);
  tetcomplexiterate(&pos, nexttet);
  while (nexttet[0] != STOP) {
    printf("  Vertex tags");
    for (i = 0; i < 4; i++) {
      if (nexttet[i] == GHOSTVERTEX) {
        printf(" GHOST");
      } else {
        printf(" %lu", (unsigned long) nexttet[i]);
      }
    }
    printf("\n");
    tetcomplexiterate(&pos, nexttet);
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexprintstars()   Print the stars in a tetcomplex.                */
/*                                                                           */
/*  This procedure prints every _copy_ of every tetrahedron in the data      */
/*  structure, so it exposes the underlying implementation, and the fact     */
/*  that each solid tetrahedron is stored in the link rings of two, three,   */
/*  or six edges (depending on the parities of the tetrahedron's vertices).  */
/*                                                                           */
/*  plex:  The tetcomplex to print.                                          */
/*                                                                           */
/*****************************************************************************/

void tetcomplexprintstars(struct tetcomplex *plex) {
  struct tetcomplexstar *star;
  tag tagloop;

  printf("List of all stars in the tetcomplex:\n");
  for (tagloop = 0; tagloop < plex->nextinitindex; tagloop++) {
    star = (struct tetcomplexstar *)
           arraypoolfastlookup(&plex->stars, (arraypoolulong) tagloop);
    if (star->linkhead != STOP) {
      printf("Vertex tag %lu, ", (unsigned long) tagloop);
      link2dprint(&plex->moleculepool, star->linkhead, tagloop);
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexmissingtet()   Check whether a tetrahedron is missing from a   */
/*                           (particular) link ring where it should be.      */
/*                                                                           */
/*  This procedure checks whether the edge (vtx1, vtx2) stores a link ring,  */
/*  and if so, whether the star of (vtx1, vtx2) includes the tetrahedron     */
/*  (vtx1, vtx2, vtx3, vtx4).  If not, it prints an error message and        */
/*  returns 1.                                                               */
/*                                                                           */
/*  Ghost edges are not guaranteed to have explicitly stored link rings,     */
/*  so if one of `vtx1' or `vtx2' is a ghost vertex, this procedure does     */
/*  nothing but return 0.                                                    */
/*                                                                           */
/*  plex:  The tetcomplex to check for the presence of the tetrahedron.      */
/*  vtx1, vtx2, vtx3, vtx4:  The tags for the vertices of the tetrahedron.   */
/*    (vtx1, vtx2) is the edge whose link ring should include (vtx3, vtx4).  */
/*                                                                           */
/*  Returns 1 if the tetrahedron should be present but is missing.  Returns  */
/*  0 if the tetrahedron is present, if one of `vtx1' or `vtx2' is a ghost   */
/*  vertex, or if (vtx1, vtx2) does not store a link ring (because the two   */
/*  vertices have opposite parity).                                          */
/*                                                                           */
/*****************************************************************************/

unsigned int tetcomplexmissingtet(struct tetcomplex *plex,
                                  tag vtx1,
                                  tag vtx2,
                                  tag vtx3,
                                  tag vtx4) {
  tag adjacencies[2];
  int existflag;

  /* Are `vtx1' and `vtx2' non-ghost vertices with the same parity? */
  if (((vtx1 & 1) == (vtx2 & 1)) &&
      (vtx1 != GHOSTVERTEX) && (vtx2 != GHOSTVERTEX) &&
      ((vtx3 != GHOSTVERTEX) || (vtx4 != GHOSTVERTEX))) {
    /* Yes.  The tetrahedron (vtx1, vtx2, vtx3, vtx4) should exist in the */
    /*   link ring of (vtx1, vtx2).                                       */
    if (vtx3 != GHOSTVERTEX) {
      existflag = tetcomplexringadjacencies(plex, vtx1, vtx2, vtx3,
                                            adjacencies);
      existflag = existflag && (adjacencies[1] == vtx4);
    } else {
      existflag = tetcomplexringadjacencies(plex, vtx1, vtx2, vtx4,
                                            adjacencies);
      existflag = existflag && (adjacencies[0] == vtx3);
    }
    if (!existflag) {
      printf("  !! !! Tet x=%lu y=%lu %lu %lu is in star of edge (x, y),\n",
             (unsigned long) vtx1, (unsigned long) vtx4,
             (unsigned long) vtx2, (unsigned long) vtx3);
      printf("    but tet v=%lu w=%lu %lu %lu is not in star of (v, w).\n",
             (unsigned long) vtx1, (unsigned long) vtx2,
             (unsigned long) vtx3, (unsigned long) vtx4);
      return 1;
    }
  }

  return 0;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexconsistency()   Check whether a tetcomplex is consistent, in   */
/*                            the sense that any tetrahedron stored in the   */
/*                            complex is duplicated in the stars of all its  */
/*                            represented edges.                             */
/*                                                                           */
/*  Prints error messages if inconsistencies are found, or a reassuring      */
/*  message otherwise.                                                       */
/*                                                                           */
/*  plex:  The tetcomplex to check for internal consistency.                 */
/*                                                                           */
/*****************************************************************************/

void tetcomplexconsistency(struct tetcomplex *plex) {
  struct tetcomplexposition pos;
  tag nexttet[4];
  arraypoolulong horrors;

  printf("Checking consistency of tetrahedral complex...\n");

  horrors = 0;
  tetcomplexiteratorinit(plex, &pos);
  tetcomplexiterateall(&pos, nexttet);
  while (nexttet[0] != STOP) {
    horrors += tetcomplexmissingtet(plex, nexttet[0], nexttet[2],
                                    nexttet[3], nexttet[1]);
    horrors += tetcomplexmissingtet(plex, nexttet[0], nexttet[3],
                                    nexttet[1], nexttet[2]);
    horrors += tetcomplexmissingtet(plex, nexttet[1], nexttet[2],
                                    nexttet[0], nexttet[3]);
    horrors += tetcomplexmissingtet(plex, nexttet[1], nexttet[3],
                                    nexttet[2], nexttet[0]);
    horrors += tetcomplexmissingtet(plex, nexttet[2], nexttet[3],
                                    nexttet[0], nexttet[1]);
    tetcomplexiterateall(&pos, nexttet);
  }

  if (horrors == 0) {
      printf("  Tremble before my vast wisdom, with which "
             "I find the mesh to be consistent.\n");
  } else if (horrors == 1) {
    printf("  !! !! !! !! Precisely one oozing cyst sighted.\n");
  } else {
    printf("  !! !! !! !! %lu monstrosities witnessed.\n",
           (unsigned long) horrors);
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexdeleteorderedtet()   Delete an ordered tetrahedron from a      */
/*                                 tetcomplex.                               */
/*                                                                           */
/*  "Ordered tetrahedron" implies that the tetrahedron is deleted only from  */
/*  the star of vertex `vtx1', and therein, only from the star of edge       */
/*  (vtx1, vtx2).  This is a helper function for other tetrahedron deletion  */
/*  procedures, and is directly useful for algorithms like star splaying     */
/*  where the stars are not always mutually consistent.  If you want to keep */
/*  your tetcomplex internally consistent, you probably should not call this */
/*  procedure directly.                                                      */
/*                                                                           */
/*  Any face of the tetrahedron that is not shared by another tetrahedron    */
/*  in the star of (vtx1, vtx2) also vanishes from that star.                */
/*                                                                           */
/*  The orientation of the tetrahedron matters.  (The orientation can be     */
/*  reversed by swapping `vtx3' and `vtx4'.)  You cannot delete (1, 2, 3, 4) */
/*  by asking to delete (1, 2, 4, 3).                                        */
/*                                                                           */
/*  WARNING:  This procedure will not usually work if there is more than one */
/*  copy of `vtx3', or more than one copy of `vtx4', in the link of (vtx1,   */
/*  vtx2).  (This circumstance is not easy to create, but it's possible.)    */
/*                                                                           */
/*  plex:  The tetcomplex to delete a tetrahedron from.                      */
/*  vtx1, vtx2, vtx3, vtx4:  The tags for the vertices of the deleted        */
/*    tetrahedron, ordered so that only the star of `vtx1' changes, and      */
/*    within that star, only the star of edge (vtx1, vtx2) changes.          */
/*                                                                           */
/*  Returns one of the following values.                                     */
/*     0:  If the tetrahedron is not present in the star of the ordered edge */
/*         (vtx1, vtx2), and the tetcomplex is unchanged.                    */
/*     1:  If the triangle (vtx1, vtx2, vtx3) was deleted, and (vtx1, vtx2,  */
/*         vtx4) survives because it is a face of another tetrahedron in the */
/*         star.                                                             */
/*     2:  If (vtx1, vtx2, vtx4) was deleted, and (vtx1, vtx2, vtx3)         */
/*         survives.                                                         */
/*     3:  If both faces are deleted, but some other tetrahedron survives in */
/*         the edge's star.                                                  */
/*     7:  If both faces are deleted, leaving the ordered edge's star empty, */
/*         so the ordered edge is deleted as well.                           */
/*     8:  If the tetrahedron is deleted, but both faces survive.            */
/*                                                                           */
/*    Hence, a positive return value implies that the tetrahedron was        */
/*    deleted.  If the result is not zero, the 1's bit signifies that (vtx1, */
/*    vtx2, vtx3) is no longer in the edge's star, and the 2's bit signifies */
/*    that (vtx1, vtx2, vtx4) is no longer in the edge's star.  (If the      */
/*    result is zero, this procedure doesn't check whether the faces are     */
/*    present.)                                                              */
/*                                                                           */
/*****************************************************************************/

int tetcomplexdeleteorderedtet(struct tetcomplex *plex,
                               tag vtx1,
                               tag vtx2,
                               tag vtx3,
                               tag vtx4)
{
  struct tetcomplexstar *star;
  tag ring;
  int result;

  if (vtx1 >= plex->nextinitindex) {
    /* `vtx1' has never had a star, so the tetrahedron can't exist. */
    return 0;
  }
  /* Look up the star of vertex `vtx1'. */
  star = (struct tetcomplexstar *)
         arraypoolfastlookup(&plex->stars, (arraypoolulong) vtx1);

  /* Find the link ring for edge (vtx1, vtx2) in the star of `vtx1'. */
  ring = link2dfindring(&plex->moleculepool, plex->cache, star->linkhead,
                        vtx1, vtx2);
  if (ring == STOP) {
    /* `vtx2' is not in the link of `vtx1', so the tetrahedron can't exist. */
    return 0;
  }

  /* Attempt to delete the tetrahedron from the star of (vtx1, vtx2). */
  result = linkringdeleteedge(&plex->moleculepool, ring, vtx1, vtx3, vtx4);
  if ((result & 4) != 0) {
    /* The link ring is now empty, so deallocate it and remove `vtx2' from */
    /*   the 2D link of `vtx1'.                                            */
    linkringdelete(&plex->moleculepool, ring);
    link2ddeletevertex(&plex->moleculepool, plex->cache, star->linkhead,
                       &star->linktail, vtx1, vtx2);
  }

  /* If linkringdeleteedge() returned -1, change it to 0. */
  if (result <= 0) {
    return 0;
  }
  return result;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexdeletetet()   Delete a tetrahedron from a tetcomplex.          */
/*                                                                           */
/*  Any face or edge of the tetrahedron that is not shared by another        */
/*  tetrahedron also vanishes.                                               */
/*                                                                           */
/*  The orientation of the tetrahedron matters.  (The orientation can be     */
/*  reversed by swapping any two vertices.)  You cannot delete (1, 2, 3, 4)  */
/*  by asking to delete (1, 2, 4, 3).  However, all even permutations of the */
/*  vertices are equivalent; deleting (1, 2, 3, 4) is the same as deleting   */
/*  (2, 1, 4, 3).                                                            */
/*                                                                           */
/*  If the tetrahedral complex is not internally consistent, this procedure  */
/*  will delete whatever copies of the tetrahedron it happens to find (which */
/*  might not be all of them).  It it finds some but not all of the copies   */
/*  it expects to find, it returns -1.  This differs from                    */
/*  tetcomplexinserttet(), which rolls back the changes when it finds an     */
/*  inconsistency.                                                           */
/*                                                                           */
/*  plex:  The tetcomplex to delete a tetrahedron from.                      */
/*  vtx1, vtx2, vtx3, vtx4:  The tags for the vertices of the deleted        */
/*    tetrahedron.                                                           */
/*                                                                           */
/*  Returns one of the following values.                                     */
/*   -1:  If the tetrahedron was deleted from some, but not all, of the edge */
/*        stars in which it should have resided.  This usually means that    */
/*        the tetcomplex is (or was) not internally consistent.              */
/*    0:  If the tetrahedron cannot be deleted, and the tetcomplex is        */
/*        unchanged.                                                         */
/*    1:  If the tetrahedron was deleted successfully.                       */
/*                                                                           */
/*****************************************************************************/

int tetcomplexdeletetet(struct tetcomplex *plex,
                        tag vtx1,
                        tag vtx2,
                        tag vtx3,
                        tag vtx4)
{
  tag swaptag;
  int result;
  int deletionflag;
  int failflag;
  int i;

  if (plex->verbosity > 3) {
    printf("        Deleting tet w/tags %lu %lu %lu %lu.\n",
           (unsigned long) vtx1, (unsigned long) vtx2,
           (unsigned long) vtx3, (unsigned long) vtx4);
  }

#ifdef SELF_CHECK
  if ((vtx1 == vtx2) || (vtx1 == vtx3) || (vtx1 == vtx4) ||
      (vtx2 == vtx3) || (vtx2 == vtx4) || (vtx3 == vtx4)) {
    printf("Internal error in tetcomplexdeletetet():\n");
    printf("  Asked to delete tetrahedron with two vertices alike.\n");
    internalerror();
  }
#endif /* SELF_CHECK */

  /* No changes have been made to the tetcomplex yet. */
  deletionflag = 0;
  /* Assume we won't fail, until proven otherwise. */
  failflag = 0;

  if ((vtx1 == GHOSTVERTEX) || (vtx2 == GHOSTVERTEX) ||
      (vtx3 == GHOSTVERTEX) || (vtx4 == GHOSTVERTEX)) {
    /* Make `vtx1', `vtx2', and `vtx3' the non-ghost vertices (preserving */
    /*   the tetrahedron's orientation).                                  */
    if (vtx1 == GHOSTVERTEX) {
      vtx1 = vtx2;
      vtx2 = vtx4;
    } else if (vtx2 == GHOSTVERTEX) {
      vtx2 = vtx3;
      vtx3 = vtx4;
    } else if (vtx3 == GHOSTVERTEX) {
      vtx3 = vtx1;
      vtx1 = vtx4;
    }

    /* For each vertex with the same parity as the ghost vertex, there is  */
    /*   a ghost edge from which the tetrahedron should be deleted.  Ghost */
    /*   tetrahedra are not explicitly stored in the link rings of solid   */
    /*   edges, so ignore the solid edges.                                 */
    if ((vtx1 & 1) == (GHOSTVERTEX & 1)) {
      if (tetcomplexdeleteorderedtet(plex, vtx1, GHOSTVERTEX, vtx2, vtx3) >
          0) {
        deletionflag = 1;
      } else {
        failflag = 1;
      }
    }
    if ((vtx2 & 1) == (GHOSTVERTEX & 1)) {
      if (tetcomplexdeleteorderedtet(plex, vtx2, GHOSTVERTEX, vtx3, vtx1) >
          0) {
        deletionflag = 1;
      } else {
        failflag = 1;
      }
    }
    if ((vtx3 & 1) == (GHOSTVERTEX & 1)) {
      if (tetcomplexdeleteorderedtet(plex, vtx3, GHOSTVERTEX, vtx1, vtx2) >
          0) {
        deletionflag = 1;
      } else {
        failflag = 1;
      }
    }

    if (!failflag) {
      /* Note that this counter may be decremented even if no change was     */
      /*   made to the tetcomplex at all, simply because the GHOSTVERTEX has */
      /*   a parity opposite to that of the other three vertices.            */
      plex->ghosttetcount--;

      /*^^^ Assertion:  The tetrahedral complex is now consistent. */
#ifdef PARANOID
      tetcomplexconsistency(plex);
#endif /* PARANOID */

      return 1;
    }
  } else {
    /* Loop over all six edges of the tetrahedron. */
    for (i = 0; i < 6; i++) {
      /* If the endpoints of the edge (vtx1, vtx2) have the same parity, the */
      /*   edge's link ring is stored, so delete the tetrahedron from the    */
      /*   edge's star.                                                      */
      if ((vtx1 & 1) == (vtx2 & 1)) {
        /* Determine which vertex star stores the link for (vtx1, vtx2). */
        if ((vtx1 < vtx2) ^ ((vtx1 & 2) == (vtx2 & 2))) {
          result = tetcomplexdeleteorderedtet(plex, vtx1, vtx2, vtx3, vtx4);
        } else {
          result = tetcomplexdeleteorderedtet(plex, vtx2, vtx1, vtx4, vtx3);
        }
        if (result > 0) {
          deletionflag = 1;
        } else {
          failflag = 1;
        }
      }

      /* The following shift cycles (vtx1, vtx2) through all the edges while */
      /*   maintaining the tetrahedron's orientation.  The schedule is       */
      /*   i = 0:  1 2 3 4 => 2 3 1 4                                        */
      /*   i = 1:  2 3 1 4 => 2 4 3 1                                        */
      /*   i = 2:  2 4 3 1 => 4 3 2 1                                        */
      /*   i = 3:  4 3 2 1 => 4 1 3 2                                        */
      /*   i = 4:  4 1 3 2 => 1 3 4 2                                        */
      /*   i = 5:  1 3 4 2 => 1 2 3 4 (which isn't used).                    */
      if ((i & 1) == 0) {
        swaptag = vtx1;
        vtx1 = vtx2;
        vtx2 = vtx3;
        vtx3 = swaptag;
      } else {
        swaptag = vtx4;
        vtx4 = vtx3;
        vtx3 = vtx2;
        vtx2 = swaptag;
      }
    }

    if (!failflag) {
      /* The tetrahedron has been successfully deleted. */
      plex->tetcount--;

      /*^^^ Assertion:  The tetrahedral complex is now consistent. */
#ifdef PARANOID
      tetcomplexconsistency(plex);
#endif /* PARANOID */

      return 1;
    }
  }

  /* The tetrahedron was missing from some edge's star where it should have */
  /*   appeared, so the deletion has failed.                                */
  if (deletionflag) {
    /* Nevertheless, a partial deletion occurred and the tetcomplex changed. */
    return -1;
  }

  /* The tetcomplex didn't change. */
  return 0;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexlookup3dstar()   Return the `tetcomplexstar' record for a      */
/*                             vertex, creating one if necessary.            */
/*                                                                           */
/*  This procedure allocates memory for, and initializes, `tetcomplexstar'   */
/*  records for all uninitialized vertex stars up to and including the tag   */
/*  `vtx'.  It also allocates a 2D link for `vtx' if it doesn't already have */
/*  one; but it doesn't allocate 2D links for tags prior to `vtx'.           */
/*                                                                           */
/*  plex:  The tetcomplex in which the vertex needs a `tetcomplexstar'.      */
/*  vtx:  The tag for the vertex whose `tetcomplexstar' record is returned   */
/*        (and possibly created).                                            */
/*                                                                           */
/*  Returns a pointer to the `tetcomplexstar' record for `vtx'.              */
/*                                                                           */
/*****************************************************************************/

struct tetcomplexstar *tetcomplexlookup3dstar(struct tetcomplex *plex,
                                              tag vtx)
{
  struct tetcomplexstar *star;
  proxipoolulong allocindex;
  tag i;

  for (i = plex->nextinitindex; i <= vtx; i++) {
    /* Make sure memory is allocated for star `i'. */
    star = (struct tetcomplexstar *)
           arraypoolforcelookup(&plex->stars, (arraypoolulong) i);
    /* Initially, the 2D link is empty. */
    star->linkhead = STOP;
    star->linktail = STOP;
  }
  /* Remember where to continue next time. */
  plex->nextinitindex = i;

  /* Look up the star of vertex `vtx'. */
  star = (struct tetcomplexstar *)
         arraypoolfastlookup(&plex->stars, (arraypoolulong) vtx);
  if (star->linkhead == STOP) {
    /* Vertex `vtx' doesn't have a 2D link yet.  Allocate one, using the */
    /*   same allocation index that was used for the vertex `vtx'.       */
    if (plex->vertexpool == (struct proxipool *) NULL) {
      allocindex = 0;
    } else {
      allocindex = proxipooltag2allocindex(plex->vertexpool, vtx);
    }
    star->linkhead = link2dnew(&plex->moleculepool, allocindex);
    star->linktail = star->linkhead;
  }

  return star;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexinsertorderedtet()   Insert an ordered tetrahedron into a      */
/*                                 tetcomplex.                               */
/*                                                                           */
/*  "Ordered tetrahedron" implies that the tetrahedron is inserted only into */
/*  the star of vertex `vtx1', and therein, it is inserted only into the     */
/*  star of edge (vtx1, vtx2).  Therefore, even permutations of the vertices */
/*  are NOT equivalent in this procedure.  This is a helper procedure for    */
/*  other tetrahedron insertion procedures, and is also directly useful for  */
/*  algorithms like star splaying where the stars are not always mutually    */
/*  consistent.  If you want to keep your tetcomplex internally consistent,  */
/*  you should not call this procedure directly.                             */
/*                                                                           */
/*  The orientation of the tetrahedron matters.  (The orientation can be     */
/*  reversed by swapping `vtx3' and `vtx4'.)  Inserting (1, 2, 3, 4) is not  */
/*  the same as inserting (1, 2, 4, 3).                                      */
/*                                                                           */
/*  This procedure will return 0 and leave the tetcomplex unchanged if any   */
/*  of the following is true.                                                */
/*                                                                           */
/*  - There is already a tetrahedron (vtx1, vtx2, vtx3, X) for some X in the */
/*    star of the ordered edge (vtx1, vtx2).                                 */
/*  - There is already a tetrahedron (vtx1, vtx2, X, vtx4) for some X in the */
/*    star of the ordered edge (vtx1, vtx2).                                 */
/*  - The link of the ordered edge (vtx1, vtx2) is truly a ring, with no     */
/*    place to insert a new tetrahedron.                                     */
/*  - The link of the ordered edge (vtx1, vtx2) currently consists of two or */
/*    more chains, and the introduction of edge (vtx3, vtx4) into the link   */
/*    will glue one of the chains into a ring.  It's not topologically       */
/*    possible (in a tetrahedral complex embeddable in 3D space) for an edge */
/*    to have a link with a ring AND a chain.                                */
/*                                                                           */
/*  WARNING:  This procedure will not usually work if there is more than one */
/*  copy of `vtx3', or more than one copy of `vtx4', in the link of (vtx1,   */
/*  vtx2).  (This circumstance is not easy to create, but it's possible.)    */
/*                                                                           */
/*  plex:  The tetcomplex to insert a tetrahedron into.                      */
/*  vtx1, vtx2, vtx3, vtx4:  The tags for the vertices of the new            */
/*    tetrahedron, ordered so that only the star of `vtx1' changes, and      */
/*    within that star, only the star of edge (vtx1, vtx2) changes.          */
/*                                                                           */
/*  Returns one of the following values.                                     */
/*    0:  If the tetrahedron cannot be inserted, and the tetcomplex is       */
/*        unchanged.                                                         */
/*    1:  If the triangle (vtx1, vtx2, vtx3) is new in the star of the       */
/*        ordered edge (vtx1, vtx2), and (vtx1, vtx2, vtx4) was already      */
/*        present.                                                           */
/*    2:  If the triangle (vtx1, vtx2, vtx4) is new in the star of the       */
/*        ordered edge (vtx1, vtx2), and (vtx1, vtx2, vtx3) was already      */
/*        present.                                                           */
/*    3:  If neither triangle was present, and both are new.                 */
/*    4:  If both triangles (vtx1, vtx2, vtx3) and (vtx1, vtx2, vtx4) were   */
/*        already present in the star of (vtx1, vtx2), and the new           */
/*        tetrahedron slid nicely between them.                              */
/*                                                                           */
/*  Hence, the 1's bit signifies that (vtx1, vtx2, vtx3) was created anew,   */
/*  and the 2's bit signifies that (vtx1, vtx2, vtx4) was created anew.      */
/*                                                                           */
/*****************************************************************************/

int tetcomplexinsertorderedtet(struct tetcomplex *plex,
                               tag vtx1,
                               tag vtx2,
                               tag vtx3,
                               tag vtx4)
{
  struct tetcomplexstar *star;
  tag ring;

  /* Make sure `vtx1' has a 2D star, and find it. */
  star = tetcomplexlookup3dstar(plex, vtx1);
  /* Find the link ring for edge (vtx1, vtx2) in the star of `vtx1'. */
  ring = link2dfindinsert(&plex->moleculepool, plex->cache, star->linkhead,
                          &star->linktail, vtx1, vtx2);
  /* Insert the tetrahedron into the star of the ordered edge (vtx1, vtx2). */
  return linkringinsertedge(&plex->moleculepool, ring, vtx1, vtx3, vtx4);
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexinserttet()   Insert a tetrahedron into a tetcomplex.          */
/*                                                                           */
/*  The orientation of the tetrahedron matters.  (The orientation can be     */
/*  reversed by swapping any two vertices.)  Inserting (1, 2, 3, 4) is not   */
/*  the same as inserting (1, 2, 4, 3).  However, all even permutations of   */
/*  the vertices are equivalent; (1, 2, 3, 4) is the same as (2, 1, 4, 3).   */
/*                                                                           */
/*  This procedure will return 0 and leave the link ring unchanged if any of */
/*  the following is true.                                                   */
/*                                                                           */
/*  - Some tetrahedron already in the complex has a face in common with the  */
/*    new tetrahedron, and both tetrahedra would be on the same side of that */
/*    face.  For example, there is already a tetrahedron (vtx1, vtx2, X,     */
/*    vtx4) for some vertex X.                                               */
/*  - One of the edges of the new tetrahedron has a full complement of       */
/*    tetrahedra encircling it.  In other words, the edge's link is a ring.  */
/*  - One of the edges of the new tetrahedron has a link consisting of two   */
/*    or more chains, and the introduction of the new tetrahedron will glue  */
/*    one of the chains into a ring.  It's not topologically possible to     */
/*    have a link with a ring AND a chain.                                   */
/*                                                                           */
/*  plex:  The tetcomplex to insert a tetrahedron into.                      */
/*  vtx1, vtx2, vtx3, vtx4:  The tags for the vertices of the new            */
/*    tetrahedron.                                                           */
/*                                                                           */
/*  Returns one of the following values.                                     */
/*    0:   If the tetrahedron cannot be inserted, and the tetcomplex is      */
/*         unchanged.                                                        */
/*    1:   If a ghost tetrahedron was inserted successfully.                 */
/*    2:   If a solid tetrahedron was inserted successfully, and the number  */
/*         of boundary triangles decreased by 4.                             */
/*    4:   If a solid tetrahedron was inserted successfully, and the number  */
/*         of boundary triangles decreased by 2.                             */
/*    6:   If a solid tetrahedron was inserted successfully, and the number  */
/*         of boundary triangles remained constant.                          */
/*    8:   If a solid tetrahedron was inserted successfully, and the number  */
/*         of boundary triangles increased by 2.                             */
/*    10:  If a solid tetrahedron was inserted successfully, and the number  */
/*         of boundary triangles increased by 4.                             */
/*                                                                           */
/*****************************************************************************/

int tetcomplexinserttet(struct tetcomplex *plex,
                        tag vtx1,
                        tag vtx2,
                        tag vtx3,
                        tag vtx4)
{
  tag lasthead = 0;
  tag lasttail = 0;
  tag swaptag;
  int result = 0;
  int linkringchanges;
  int deltafaces;
  int i;

  if (plex->verbosity > 3) {
    printf("        Inserting tet w/tags %lu %lu %lu %lu.\n",
           (unsigned long) vtx1, (unsigned long) vtx2,
           (unsigned long) vtx3, (unsigned long) vtx4);
  }

#ifdef SELF_CHECK
  if ((vtx1 == vtx2) || (vtx1 == vtx3) || (vtx1 == vtx4) ||
      (vtx2 == vtx3) || (vtx2 == vtx4) || (vtx3 == vtx4)) {
    printf("Internal error in tetcomplexinserttet():\n");
    printf("  Asked to insert tetrahedron with two vertices alike.\n");
    internalerror();
  }
#endif /* SELF_CHECK */

  /* No changes have been made to the tetcomplex yet. */
  linkringchanges = 0;

  if ((vtx1 == GHOSTVERTEX) || (vtx2 == GHOSTVERTEX) ||
      (vtx3 == GHOSTVERTEX) || (vtx4 == GHOSTVERTEX)) {
    /* Make `vtx1', `vtx2', and `vtx3' the non-ghost vertices (preserving */
    /*   the tetrahedron's orientation).                                  */
    if (vtx1 == GHOSTVERTEX) {
      vtx1 = vtx2;
      vtx2 = vtx4;
    } else if (vtx2 == GHOSTVERTEX) {
      vtx2 = vtx3;
      vtx3 = vtx4;
    } else if (vtx3 == GHOSTVERTEX) {
      vtx3 = vtx1;
      vtx1 = vtx4;
    }

    /* For each vertex with the same parity as the ghost vertex, there is */
    /*   (or will be) a ghost edge.  Store the ghost tetrahedron in the   */
    /*   star of the ghost edge.  Note that ghost tetrahedra are not      */
    /*   explicitly stored in the link rings of solid edges, but they are */
    /*   implicitly already there if the ghost tetrahedra are consistent  */
    /*   with the solid tetrahedra.                                       */
    if ((vtx1 & 1) == (GHOSTVERTEX & 1)) {
      if (tetcomplexinsertorderedtet(plex, vtx1, GHOSTVERTEX, vtx2, vtx3) <=
          0) {
        return 0;
      }
      linkringchanges = 1;
    }
    if ((vtx2 & 1) == (GHOSTVERTEX & 1)) {
      if (tetcomplexinsertorderedtet(plex, vtx2, GHOSTVERTEX, vtx3, vtx1) <=
          0) {
        if (linkringchanges) {
          /* Roll back the change that has been made. */
          tetcomplexdeleteorderedtet(plex, vtx1, GHOSTVERTEX, vtx2, vtx3);
        }
        return 0;
      }
      linkringchanges = linkringchanges | 2;
    }
    if ((vtx3 & 1) == (GHOSTVERTEX & 1)) {
      if (tetcomplexinsertorderedtet(plex, vtx3, GHOSTVERTEX, vtx1, vtx2) <=
          0) {
        if ((linkringchanges & 1) != 0) {
          /* Roll back the change. */
          tetcomplexdeleteorderedtet(plex, vtx1, GHOSTVERTEX, vtx2, vtx3);
        }
        if ((linkringchanges & 2) != 0) {
          /* Roll back the change. */
          tetcomplexdeleteorderedtet(plex, vtx2, GHOSTVERTEX, vtx3, vtx1);
        }
        return 0;
      }
    }

    /* Note that this counter may be incremented even if no change was made */
    /*   to the tetcomplex at all, simply because the GHOSTVERTEX has a     */
    /*   parity opposite to that of the other three vertices.               */
    plex->ghosttetcount++;

    /*^^^ Assertion:  The tetrahedral complex is now consistent. */
#ifdef PARANOID
    tetcomplexconsistency(plex);
#endif /* PARANOID */

    return 1;
  }

  /* No triangular boundary faces have been created/covered yet. */
  deltafaces = 0;

  /* Loop over all six edges of the tetrahedron. */
  for (i = 0; i < 6; i++) {
    /* If the endpoints of the edge (vtx1, vtx2) have the same parity, the */
    /*   edge's link ring is stored, so insert the new tetrahedron into    */
    /*   the edge's star.                                                  */
    if ((vtx1 & 1) == (vtx2 & 1)) {
      /* Determine which vertex star stores the link for (vtx1, vtx2). */
      if ((vtx1 < vtx2) ^ ((vtx1 & 2) == (vtx2 & 2))) {
        result = tetcomplexinsertorderedtet(plex, vtx1, vtx2, vtx3, vtx4);
        lasthead = vtx1;
        lasttail = vtx4;
      } else {
        result = tetcomplexinsertorderedtet(plex, vtx2, vtx1, vtx4, vtx3);
        lasthead = vtx2;
        lasttail = vtx3;
      }
      if (result == 3) {
        /* Two new triangular faces are on the boundary. */
        deltafaces += 2;
      } else if (result == 4) {
        /* Two triangular faces are covered, and no longer on the boundary. */
        deltafaces -= 2;
      } else if (result <= 0) {
        /* The insertion failed.  If any previous insertions were */
        /*   successful, roll back the changes that were made.    */
        if (linkringchanges != 0) {
          tetcomplexdeletetet(plex, vtx1, vtx2, vtx3, vtx4);
        }
        return 0;
      }
      /* Count the number of edges whose link rings have changed. */
      linkringchanges++;
    }

    /* The following rotation cycles (vtx1, vtx2) through all the edges    */
    /*   while maintaining the tetrahedron's orientation.  The schedule is */
    /*   i = 0:  1 2 3 4 => 2 3 1 4                                        */
    /*   i = 1:  2 3 1 4 => 2 4 3 1                                        */
    /*   i = 2:  2 4 3 1 => 4 3 2 1                                        */
    /*   i = 3:  4 3 2 1 => 4 1 3 2                                        */
    /*   i = 4:  4 1 3 2 => 1 3 4 2                                        */
    /*   i = 5:  1 3 4 2 => 1 2 3 4 (which isn't used).                    */
    if ((i & 1) == 0) {
      swaptag = vtx1;
      vtx1 = vtx2;
      vtx2 = vtx3;
      vtx3 = swaptag;
    } else {
      swaptag = vtx4;
      vtx4 = vtx3;
      vtx3 = vtx2;
      vtx2 = swaptag;
    }
  }

  /* The tetrahedron has been successfully inserted. */
  plex->tetcount++;

  /*^^^ Assertion:  The tetrahedral complex is now consistent. */
#ifdef PARANOID
  tetcomplexconsistency(plex);
#endif /* PARANOID */

  /* `linkringchanges' can be 2, 3, or 6, depending on the parities of       */
  /*   the vertices.  If it's 2, then only two (opposing) edges of the       */
  /*   tetrahedron have link rings, so the change `deltafaces' in the number */
  /*   of boundary faces was counted correctly.  Otherwise, it needs to be   */
  /*   adjusted.                                                             */
  if (linkringchanges == 3) {
    /* One of the face's changes was counted three times (that face being  */
    /*   the one opposite the vertex whose parity disagrees with the other */
    /*   three vertices), whereas the other three faces' changes were each */
    /*   counted once.                                                     */
    if (deltafaces > 0) {
      /* A newly created boundary face was counted thrice. */
      deltafaces -= 2;
    } else if (deltafaces < 0) {
      /* A covered boundary face was counted thrice. */
      deltafaces += 2;
    } else {
      /* The face that was counted three times cancels out the other three  */
      /*   faces.  Therefore, `deltafaces' is zero, and `result' is either  */
      /*   1 or 2.  Was a new boundary face counted three times, or was a   */
      /*   covered boundary face counted thrice?  If `lasttail' has parity  */
      /*   opposite to `lasthead', then `lasttail' is the parity-mismatched */
      /*   vertex.                                                          */
      if (((lasttail & 1) != (lasthead & 1)) ^ (result == 1)) {
        /* Either `lasttail' is the parity-mismatched vertex and             */
        /*   result == 2, in which case a boundary face opposite `lasttail'  */
        /*   got covered (is no longer on the boundary) and counted thrice;  */
        /*   or `lasttail' matches two other vertices' parity and            */
        /*   result == 1, in which case a boundary face adjoining `lasttail' */
        /*   got covered and counted thrice.                                 */
        deltafaces += 2;
      } else {
        /* Reversing the reasoning above, a new boundary face got counted */
        /*   thrice.                                                      */
        deltafaces -= 2;
      }
    }
  } else if (linkringchanges == 6) {
    /* All four vertices have the same parity, so all six edges of the */
    /*   tetrahedron have link rings, so every face change was counted */
    /*   thrice.                                                       */
    deltafaces /= 3;
  }
  return 6 + deltafaces;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplex12fliponedge()   Replace a tetrahedron with two in an edge's   */
/*                             star.                                         */
/*                                                                           */
/*  Replaces the tetrahedron (vtx1, vtx2, vtx3, vtx4) with (vtx1, vtx2,      */
/*  vtx3, newvertex) and (vtx1, vtx2, newvertex, vtx4) in the star of the    */
/*  edge (vtx1, vtx2).  If `vtx1' and `vtx2' have opposite parities, this    */
/*  procedure assumes that the edge is not stored, and does nothing.         */
/*                                                                           */
/*  Equivalently, this procedure replace one edge with two in the link       */
/*  ring of the edge (vtx1, vtx2).  This is accomplished by inserting a      */
/*  vertex `newvertex' between `vxt3' and `vtx4' in the link ring.           */
/*                                                                           */
/*  This is a helper procedure for other procedures.  Used in isolation, it  */
/*  changes the complex so the stars are not mutually consistent.  If you    */
/*  want to keep your tetcomplex internally consistent, you probably should  */
/*  not call this procedure directly.                                        */
/*                                                                           */
/*  WARNING:  This procedure does not check whether the tetrahedron (vtx1,   */
/*  vtx2, vtx3, vtx4) is in the vertex's star.  If the tetrahedron is not    */
/*  there, `newvertex' may be inserted in the link ring, next to `vtx3' or   */
/*  `vtx4', or the program may halt with an internal error.  Don't call this */
/*  procedure unless you're sure the tetrahedron is in the edge's star (if   */
/*  the edge is stored at all).                                              */
/*                                                                           */
/*  plex:  The tetcomplex in which the flip occurs.                          */
/*  vtx1, vtx2, vtx3, vtx4:  The tags for the vertices of the tetrahedron    */
/*    being replaced.  (vtx1, vtx2) is the edge whose star is changed.       */
/*  newvertex:  Tag for the vertex to be inserted between `vtx3' and `vtx4'  */
/*    in the link ring.                                                      */
/*                                                                           */
/*****************************************************************************/

void tetcomplex12fliponedge(struct tetcomplex *plex,
                            tag vtx1,
                            tag vtx2,
                            tag vtx3,
                            tag vtx4,
                            tag newvertex)
{
  struct tetcomplexstar *star;
  tag ring;
  tag swaptag;
  int result;

  /* The edge (vtx1, vtx2) is stored only if vtx1 and vtx2 have the */
  /*   same parity.                                                 */
  if ((vtx1 & 1) != (vtx2 & 1)) {
    return;
  }

  /* Determine which vertex's star stores the edge's link ring. */
  if (!((vtx2 == GHOSTVERTEX) ||
        ((vtx1 != GHOSTVERTEX) &&
         ((vtx1 < vtx2) ^ ((vtx1 & 2) == (vtx2 & 2)))))) {
    /* `vtx2' stores the link ring, so swap it with `vtx1'.  To preserve the */
    /*   tetrahedron orientation, `vtx4' replaces `vtx3'.                    */
    swaptag = vtx1;
    vtx1 = vtx2;
    vtx2 = swaptag;
    vtx3 = vtx4;
  }

  /* Has a star ever been allocated for vtx1? */
  if (vtx1 < plex->nextinitindex) {
    /* Insert `newvertex' after `vtx3' in the link ring for (vtx1, vtx2). */
    star = (struct tetcomplexstar *)
           arraypoolfastlookup(&plex->stars, (arraypoolulong) vtx1);
    ring = link2dfindring(&plex->moleculepool, plex->cache, star->linkhead,
                          vtx1, vtx2);
    result = linkringinsertvertex(&plex->moleculepool, ring,
                                  vtx1, vtx3, newvertex);
    if (result <= 0) {
      printf("Internal error in tetcomplex12fliponedge():\n");
      printf("  Tetrahedron is missing from the edge's star.\n");
      internalerror();
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexinserttetontripod()   Insert a tetrahedron into the link rings */
/*                                  of three edges that meet at `vtx1',      */
/*                                  forming a "tripod".                      */
/*                                                                           */
/*  This is a special-purpose procedure designed to help ease and speed up   */
/*  the Bowyer-Watson algorithm.  It should not normally be used by other    */
/*  algorithms.                                                              */
/*                                                                           */
/*  This procedure is similar to tetcomplexinserttet(), but it only modifies */
/*  the link rings of three of the tetrahedron's six edges--the three edges  */
/*  that meet at `vtx1'.  (Note that this is NOT the same as changing only   */
/*  the star of `vtx1'; the three edges might be stored with the other       */
/*  vertices, and both endpoints of each edge are presumed to have had       */
/*  their stars changed.)  This procedure can introduce (or repair)          */
/*  inconsistencies _within_ the stars of `vtx2', `vtx3', and `vtx4', which  */
/*  the Bowyer-Watson implementation eventually repairs.                     */
/*                                                                           */
/*  This procedure will return 0 and leave the link ring under roughly the   */
/*  same circumstances as tetcomplexinserttet(), although this procedure     */
/*  does not check the edges it doesn't modify.                              */
/*                                                                           */
/*  plex:  The tetcomplex to insert a tetrahedron into.                      */
/*  vtx1, vtx2, vtx3, vtx4:  The tags for the vertices of the new            */
/*    tetrahedron.  Only edges adjoining `vtx1' have their stars modified.   */
/*                                                                           */
/*  Returns one of the following values.                                     */
/*    0:  If the tetrahedron cannot be inserted, and the tetcomplex is       */
/*        unchanged.                                                         */
/*    1:  If the tetrahedron was inserted successfully.                      */
/*                                                                           */
/*****************************************************************************/

int tetcomplexinserttetontripod(struct tetcomplex *plex,
                                tag vtx1,
                                tag vtx2,
                                tag vtx3,
                                tag vtx4)
{
  tag swaptag;
  int result;
  int insertionflag;
  int i;

  if (plex->verbosity > 3) {
    printf("        Inserting tet w/tags %lu %lu %lu %lu\n"
           "          in stars of edges adjoining vertex tag %lu.\n",
           (unsigned long) vtx1, (unsigned long) vtx2,
           (unsigned long) vtx3, (unsigned long) vtx4, (unsigned long) vtx1);
  }

#ifdef SELF_CHECK
  if (vtx1 >= STOP) {
    printf("Internal error in tetcomplexinserttetontripod():\n");
    printf("  First parameter is not a valid vertex tag.\n");
    internalerror();
  }
  if ((vtx1 == vtx2) || (vtx1 == vtx3) || (vtx1 == vtx4) ||
      (vtx2 == vtx3) || (vtx2 == vtx4) || (vtx3 == vtx4)) {
    printf("Internal error in tetcomplexinserttetontripod():\n");
    printf("  Asked to insert tetrahedron with two vertices alike.\n");
    internalerror();
  }
#endif /* SELF_CHECK */

  /* No changes have been made to the tetcomplex yet. */
  insertionflag = 0;

  result = 1;
  if ((vtx2 == GHOSTVERTEX) || (vtx3 == GHOSTVERTEX) ||
      (vtx4 == GHOSTVERTEX)) {
    /* A ghost tetrahedron changes only a ghost edge's link ring.  `vtx1'   */
    /*   stores a ghost edge only if it has the same parity as GHOSTVERTEX. */
    if ((vtx1 & 1) == (GHOSTVERTEX & 1)) {
      /* Insert the ghost tetrahedron into a ghost edge's star. */
      if (vtx2 == GHOSTVERTEX) {
        if (tetcomplexinsertorderedtet(plex,
                                       vtx1, GHOSTVERTEX, vtx3, vtx4) == 0) {
          return 0;
        }
      } else if (vtx3 == GHOSTVERTEX) {
        if (tetcomplexinsertorderedtet(plex,
                                       vtx1, GHOSTVERTEX, vtx4, vtx2) == 0) {
          return 0;
        }
      } else {
        /* vtx4 == GHOSTVERTEX */
        if (tetcomplexinsertorderedtet(plex,
                                       vtx1, GHOSTVERTEX, vtx2, vtx3) == 0) {
          return 0;
        }
      }
    }

    /* Note that this counter may be incremented even if no change was */
    /*   made to the tetcomplex at all, simply because `vtx1' and the  */
    /*   GHOSTVERTEX have opposite parities.                           */
    plex->ghosttetcount++;
    return 1;
  } else {
    /* Loop over the three edges of the tetrahedron adjoining `vtx1'. */
    for (i = 0; i < 3; i++) {
      /* If the endpoints of the edge (vtx1, vtx2) have the same parity, the */
      /*   edge's link ring is stored, so insert the new tetrahedron into    */
      /*   the edge's star.                                                  */
      if ((vtx1 & 1) == (vtx2 & 1)) {
        /* Determine which vertex star stores the link for (vtx1, vtx2). */
        if ((vtx1 < vtx2) ^ ((vtx1 & 2) == (vtx2 & 2))) {
          result = tetcomplexinsertorderedtet(plex, vtx1, vtx2, vtx3, vtx4);
        } else {
          result = tetcomplexinsertorderedtet(plex, vtx2, vtx1, vtx4, vtx3);
        }
        if (result <= 0) {
          /* The insertion failed.  If any previous insertions were */
          /*   successful, roll back the changes that were made.    */
          if (insertionflag) {
            tetcomplexdeleteorderedtet(plex, vtx1, vtx2, vtx3, vtx4);
            tetcomplexdeleteorderedtet(plex, vtx2, vtx1, vtx4, vtx3);
            tetcomplexdeleteorderedtet(plex, vtx1, vtx3, vtx4, vtx2);
            tetcomplexdeleteorderedtet(plex, vtx3, vtx1, vtx2, vtx4);
          }
          return 0;
        }
        /* Remember this change in case it needs to be rolled back later. */
        insertionflag = 1;
      }

      /* The following shift cycles (vtx1, vtx2) through the edges adjoining */
      /*   `vtx1' while maintaining the tetrahedron's orientation.           */
      swaptag = vtx2;
      vtx2 = vtx3;
      vtx3 = vtx4;
      vtx4 = swaptag;
    }

    /* Note that this counter may be incremented even if no change was */
    /*   made to the tetcomplex at all, simply because `vtx1' has a    */
    /*   parity opposite to that of the other three vertices.          */
    plex->tetcount++;
    return 1;
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplex21fliponedge()   Replace two adjacent tetrahedra with one in   */
/*                             an edge's star.                               */
/*                                                                           */
/*  Replaces the tetrahedra (vtx1, vtx2, X, vtx3) and (vtx1, vtx2, vtx3, Y)  */
/*  with (vtx1, vtx2, X, Y) in the star of the edge (vtx1, vtx2).  If `vtx1' */
/*  and `vtx2' have opposite parities, this procedure assumes that the edge  */
/*  is not stored, and does nothing.                                         */
/*                                                                           */
/*  Equivalently, this procedure replace two edges with one in the link      */
/*  ring of the edge (vtx1, vtx2).  This is accomplished by deleting a       */
/*  vertex `vtx3' from the link ring.                                        */
/*                                                                           */
/*  This is a helper procedure for other procedures.  Used in isolation, it  */
/*  changes the complex so the stars are not mutually consistent.  If you    */
/*  want to keep your tetcomplex internally consistent, you probably should  */
/*  not call this procedure directly.                                        */
/*                                                                           */
/*  WARNING:  don't call this procedure unless you're sure `vtx3' is in the  */
/*  edge's link ring (if the edge is stored at all).                         */
/*                                                                           */
/*  plex:  The tetcomplex in which the flip occurs.                          */
/*  vtx1, vtx2, vtx3:  The tags for the vertices of the triangle being       */
/*    deleted.  (vtx1, vtx2) is the edge whose star is changed.              */
/*                                                                           */
/*****************************************************************************/

void tetcomplex21fliponedge(struct tetcomplex *plex,
                            tag vtx1,
                            tag vtx2,
                            tag vtx3)
{
  struct tetcomplexstar *star;
  tag ring;
  tag swaptag;
  int result;

  /* The edge (vtx1, vtx2) is stored only if vtx1 and vtx2 have the */
  /*   same parity.                                                 */
  if ((vtx1 & 1) != (vtx2 & 1)) {
    return;
  }

  /* Determine which vertex's star stores the edge's link ring. */
  if (!((vtx2 == GHOSTVERTEX) ||
        ((vtx1 != GHOSTVERTEX) &&
         ((vtx1 < vtx2) ^ ((vtx1 & 2) == (vtx2 & 2)))))) {
    /* `vtx2' stores the link ring, so swap it with `vtx1'. */
    swaptag = vtx1;
    vtx1 = vtx2;
    vtx2 = swaptag;
  }

  /* Has a star ever been allocated for vtx1? */
  if (vtx1 < plex->nextinitindex) {
    /* Delete `vtx3' from the link ring for (vtx1, vtx2). */
    star = (struct tetcomplexstar *)
           arraypoolfastlookup(&plex->stars, (arraypoolulong) vtx1);
    ring = link2dfindring(&plex->moleculepool, plex->cache, star->linkhead,
                          vtx1, vtx2);
    result = linkringdeletevertex(&plex->moleculepool, ring, vtx1, vtx3);
    if ((result & 2) != 0) {
      /* Link ring now empty; free it and remove vtx2 from vtx1's 2D link. */
      linkringdelete(&plex->moleculepool, ring);
      link2ddeletevertex(&plex->moleculepool, plex->cache, star->linkhead,
                         &star->linktail, vtx1, vtx2);
    }
    if (result <= 0) {
      printf("Internal error in tetcomplex21fliponedge():\n");
      printf("  Triangle is missing from the edge's star.\n");
      internalerror();
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexdeletetriangle()   Delete a triangle from a tetcomplex, gluing */
/*                               the two adjoining tetrahedra (or one        */
/*                               tetrahedron and one polyhedron) together    */
/*                               into a single polyhedron.                   */
/*                                                                           */
/*  This is a special-purpose procedure designed to help ease and speed up   */
/*  the Bowyer-Watson algorithm.  It should not normally be used by other    */
/*  algorithms.                                                              */
/*                                                                           */
/*  To understand this procedure, it's useful to think of each edge's link   */
/*  ring not as a bunch of tetrahedra encircling an edge, but as a bunch of  */
/*  triangles encircling an edge, acting as boundaries in a polyhedral       */
/*  complex.  The Blandford et al. data structure can represent arbitrary    */
/*  polyhedral complexes (with all faces triangulated)--although to support  */
/*  efficient adjacency queries, you would need to store all the edges (not  */
/*  just half the edges, as Blandford et al. do).                            */
/*                                                                           */
/*  This procedure deletes a triangle (vtx1, vtx2, vtx3) from the complex,   */
/*  thereby uniting the two polyhedra adjoining the face into a single       */
/*  polyhedron.  It is used by the Bowyer-Watson implementation to unite all */
/*  the tetrahedra that are no longer Delaunay into one polyhedral cavity,   */
/*  which is subsequently filled with new tetrahedra.                        */
/*                                                                           */
/*  plex:  The tetcomplex to delete a triangle from.                         */
/*  vtx1, vtx2, vtx3:  The tags for the vertices of the triangle to delete.  */
/*                                                                           */
/*****************************************************************************/

void tetcomplexdeletetriangle(struct tetcomplex *plex,
                              tag vtx1,
                              tag vtx2,
                              tag vtx3)
{
  if (plex->verbosity > 3) {
    printf("        Deleting triangle w/tags %lu %lu %lu.\n",
           (unsigned long) vtx1, (unsigned long) vtx2, (unsigned long) vtx3);
  }

  tetcomplex21fliponedge(plex, vtx1, vtx2, vtx3);
  tetcomplex21fliponedge(plex, vtx2, vtx3, vtx1);
  tetcomplex21fliponedge(plex, vtx3, vtx1, vtx2);
}

void tetcomplexsqueezeonhalfedge(struct tetcomplex *plex,
                                 tag vtx1,
                                 tag vtx2,
                                 tag vtx3)
{
  struct tetcomplexstar *star;
  tag ring;
  int result;

  if (vtx1 < plex->nextinitindex) {
    star = (struct tetcomplexstar *)
           arraypoolfastlookup(&plex->stars, (arraypoolulong) vtx1);
    ring = link2dfindring(&plex->moleculepool, plex->cache, star->linkhead,
                          vtx1, vtx2);
    result = linkringdelete2vertices(&plex->moleculepool, ring, vtx1, vtx3);
    if ((result & 2) != 0) {
      linkringdelete(&plex->moleculepool, ring);
      link2ddeletevertex(&plex->moleculepool, plex->cache, star->linkhead,
                         &star->linktail, vtx1, vtx2);
    }
    if (result < 1) {
      printf("Oops.\n");
    }
  } else {
    printf("Oops.\n");
  }
}

void tetcomplexsqueezeonedge(struct tetcomplex *plex,
                             tag vtx1,
                             tag vtx2,
                             tag vtx3)
{
  if ((vtx1 & 1) == (vtx2 & 1)) {
    if ((vtx2 == GHOSTVERTEX) ||
        ((vtx1 != GHOSTVERTEX) &&
         ((vtx1 < vtx2) ^ ((vtx1 & 2) == (vtx2 & 2))))) {
      tetcomplexsqueezeonhalfedge(plex, vtx1, vtx2, vtx3);
    } else {
      tetcomplexsqueezeonhalfedge(plex, vtx2, vtx1, vtx3);
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexsqueezetriangle()   Delete a triangle from a tetcomplex, in    */
/*                                the case where both tetrahedra adjoining   */
/*                                the triangle have the same apex.           */
/*                                                                           */
/*  This is a special-purpose procedure designed to help ease and speed up   */
/*  the Bowyer-Watson algorithm.  It should not normally be used by other    */
/*  algorithms.                                                              */
/*                                                                           */
/*  To understand this procedure, it's useful to think of each edge's link   */
/*  ring not as a bunch of tetrahedra encircling an edge, but as a bunch of  */
/*  triangles encircling an edge, acting as boundaries in a polyhedral       */
/*  complex.  The Blandford et al. data structure can represent arbitrary    */
/*  polyhedral complexes (with all faces triangulated)--although to support  */
/*  efficient adjacency queries, you would need to store all the edges (not  */
/*  just half the edges, as Blandford et al. do).                            */
/*                                                                           */
/*  This procedure deletes a triangle (vtx1, vtx2, vtx3) from the complex,   */
/*  in the special case where both tetrahedra, on each side of it, have      */
/*  already been "carved out" from the Bowyer-Watson cavity.  In this case,  */
/*  the triangle itself is not Delaunay and must be deleted also.  However,  */
/*  it is in a transient state where the newly inserted vertex appears on    */
/*  both sides of the triangle.  So when the triangle is deleted, one of     */
/*  the duplicate copies of the new vertex must also be deleted.             */
/*                                                                           */
/*  One or more edges of the triangle may be deleted (with their link        */
/*  rings).  This happens when the new vertex is the only vertex that would  */
/*  be left in the link ring.                                                */
/*                                                                           */
/*  plex:  The tetcomplex to delete a triangle from.                         */
/*  vtx1, vtx2, vtx3:  The tags for the vertices of the triangle to delete.  */
/*                                                                           */
/*****************************************************************************/

void tetcomplexsqueezetriangle(struct tetcomplex *plex,
                               tag vtx1,
                               tag vtx2,
                               tag vtx3)
{
  if (plex->verbosity > 3) {
    printf("        Squeezing triangle w/tags %lu %lu %lu.\n",
           (unsigned long) vtx1, (unsigned long) vtx2, (unsigned long) vtx3);
  }

  tetcomplexsqueezeonedge(plex, vtx1, vtx2, vtx3);
  tetcomplexsqueezeonedge(plex, vtx2, vtx3, vtx1);
  tetcomplexsqueezeonedge(plex, vtx3, vtx1, vtx2);
}

void tetcomplex12flipon3edges(struct tetcomplex *plex,
                              tag vtx1,
                              tag vtx2,
                              tag vtx3,
                              tag vtx4,
                              tag newvertex)
{
  if (plex->verbosity > 3) {
    printf("        Inserting vertex into stars of 3 edges:\n");
    printf("          Tags %lu %lu %lu %lu; new vertex %lu.\n",
           (unsigned long) vtx1, (unsigned long) vtx2, (unsigned long) vtx3,
           (unsigned long) vtx4, (unsigned long) newvertex);
  }

  tetcomplex12fliponedge(plex, vtx1, vtx2, vtx3, vtx4, newvertex);
  tetcomplex12fliponedge(plex, vtx1, vtx3, vtx4, vtx2, newvertex);
  tetcomplex12fliponedge(plex, vtx1, vtx4, vtx2, vtx3, newvertex);
  if ((vtx1 == GHOSTVERTEX) || (vtx2 == GHOSTVERTEX) ||
      (vtx3 == GHOSTVERTEX) || (vtx4 == GHOSTVERTEX)) {
    /* A ghost tetrahedron was absorbed into the cavity. */
    plex->ghosttetcount--;
  } else {
    /* A solid tetrahedron was absorbed into the cavity. */
    plex->tetcount--;
  }
}

void tetcomplex12flipon6edges(struct tetcomplex *plex,
                              tag vtx1,
                              tag vtx2,
                              tag vtx3,
                              tag vtx4,
                              tag newvertex)
{
  if (plex->verbosity > 3) {
    printf("        Inserting vertex into stars of 6 edges (tetrahedron):\n");
    printf("          Tags %lu %lu %lu %lu; new vertex %lu.\n",
           (unsigned long) vtx1, (unsigned long) vtx2, (unsigned long) vtx3,
           (unsigned long) vtx4, (unsigned long) newvertex);
  }

  tetcomplex12fliponedge(plex, vtx1, vtx2, vtx3, vtx4, newvertex);
  tetcomplex12fliponedge(plex, vtx1, vtx3, vtx4, vtx2, newvertex);
  tetcomplex12fliponedge(plex, vtx1, vtx4, vtx2, vtx3, newvertex);
  tetcomplex12fliponedge(plex, vtx2, vtx3, vtx1, vtx4, newvertex);
  tetcomplex12fliponedge(plex, vtx2, vtx4, vtx3, vtx1, newvertex);
  tetcomplex12fliponedge(plex, vtx3, vtx4, vtx1, vtx2, newvertex);
  if ((vtx4 == GHOSTVERTEX) || (vtx3 == GHOSTVERTEX) ||
      (vtx2 == GHOSTVERTEX) || (vtx1 == GHOSTVERTEX)) {
    /* The cavity start with the deletion of a ghost tetrahedron. */
    plex->ghosttetcount--;
  } else {
    /* The cavity start with the deletion of a solid tetrahedron. */
    plex->tetcount--;
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplex14flip()   Replace one tetrahedron with four (bistellar flip). */
/*                                                                           */
/*  The tetrahedron (vtx1, vtx2, vtx3, vtx4) is replaced by the tetrahedra   */
/*  (newvertex, vtx2, vtx3, vtx4), (vtx1, newvertex, vtx3, vtx4),            */
/*  (vtx1, vtx2, newvertex, vtx4), and (vtx1, vtx2, vtx3, newvertex).        */
/*  Equivalently, `newvertex' is lazily inserted in the tetrahedron.         */
/*                                                                           */
/*  This procedure is equivalent to                                          */
/*                                                                           */
/*    tetcomplexdeletetet(plex, vtx1, vtx2, vtx3, vtx4);                     */
/*    tetcomplexinserttet(plex, newvertex, vtx2, vtx3, vtx4);                */
/*    tetcomplexinserttet(plex, vtx1, newvertex, vtx3, vtx4);                */
/*    tetcomplexinserttet(plex, vtx1, vtx2, newvertex, vtx4);                */
/*    tetcomplexinserttet(plex, vtx1, vtx2, vtx3, newvertex);                */
/*                                                                           */
/*  only faster, and with less error checking.                               */
/*                                                                           */
/*  This procedure is the inverse of tetcomplex41flip().                     */
/*                                                                           */
/*  WARNING:  The tetcomplex `plex' must not contain any tetrahedra that     */
/*  have `newvertex' for a vertex.  (In other words, the star of `newvertex' */
/*  must be empty before the call.)  This procedure does not check whether   */
/*  the complex actually contains the tetrahedron (vtx1, vtx2, vtx3, vtx4),  */
/*  and may fail catastrophically if it does not.                            */
/*                                                                           */
/*  plex:  The tetcomplex containing the original tetrahedron.               */
/*  vtx1, vtx2, vtx3, vtx4:  The tags for the vertices of the tetrahedron to */
/*    flip.                                                                  */
/*  newvertex:  The tag for the new vertex to insert.                        */
/*                                                                           */
/*****************************************************************************/

void tetcomplex14flip(struct tetcomplex *plex,
                      tag vtx1,
                      tag vtx2,
                      tag vtx3,
                      tag vtx4,
                      tag newvertex)
{
  tag vtx[4];
  tag tagarray[3];
  struct tetcomplexstar *star;
  proxipoolulong allocindex;
  tag vtxowner, vtxowned;
  tag ring;
  int i;

  if (plex->verbosity > 2) {
    printf("      Transforming one tetrahedron to four (vertex insertion).\n");
    if (plex->verbosity > 3) {
      printf("        Tags %lu %lu %lu %lu; new vertex tag %lu.\n",
             (unsigned long) vtx1, (unsigned long) vtx2, (unsigned long) vtx3,
             (unsigned long) vtx4, (unsigned long) newvertex);
    }
  }

#ifdef SELF_CHECK
  if ((newvertex == vtx1) || (newvertex == vtx2) ||
      (newvertex == vtx3) || (newvertex == vtx4) ||
      (vtx1 == vtx2) || (vtx1 == vtx3) || (vtx1 == vtx4) ||
      (vtx2 == vtx3) || (vtx2 == vtx4) || (vtx3 == vtx4)) {
    printf("Internal error in tetcomplex14flip():\n");
    printf("  Asked to perform a flip with two identical vertices.\n");
    internalerror();
  }

  if (newvertex < plex->nextinitindex) {
    /* Look up the star of vertex `newvertex'. */
    star = tetcomplexlookup3dstar(plex, newvertex);
    if (!link2disempty(&plex->moleculepool, star->linkhead)) {
      printf("Internal error in tetcomplex14flip():\n");
      printf("  New vertex's star is not empty before the flip.\n");
      internalerror();
    }
  }
#endif /* SELF_CHECK */

  /* Insert six new triangles in the stars of the six edges of the original */
  /*   tetrahedron.                                                         */
  tetcomplex12fliponedge(plex, vtx1, vtx2, vtx3, vtx4, newvertex);
  tetcomplex12fliponedge(plex, vtx1, vtx3, vtx4, vtx2, newvertex);
  tetcomplex12fliponedge(plex, vtx1, vtx4, vtx2, vtx3, newvertex);
  tetcomplex12fliponedge(plex, vtx2, vtx3, vtx1, vtx4, newvertex);
  tetcomplex12fliponedge(plex, vtx2, vtx4, vtx3, vtx1, newvertex);
  tetcomplex12fliponedge(plex, vtx3, vtx4, vtx1, vtx2, newvertex);

  /* Create the four new edges and their link rings. */
  vtx[0] = vtx1;
  vtx[1] = vtx2;
  vtx[2] = vtx3;
  vtx[3] = vtx4;
  for (i = 0; i < 4; i++) {
    /* Does the edge (newvertex, vtx[i]) store a link ring?  (Parity check.) */
    if ((newvertex & 1) == (vtx[i] & 1)) {
      /* Yes.  Which of the two vertices is responsible for storing it? */
      if ((vtx[i] == GHOSTVERTEX) ||
          ((newvertex != GHOSTVERTEX) &&
           ((newvertex < vtx[i]) ^ ((newvertex & 2) == (vtx[i] & 2))))) {
        /* `newvertex' stores a new link ring containing three tetrahedra. */
        vtxowner = newvertex;
        vtxowned = vtx[i];
        tagarray[0] = vtx[i ^ 3];
        tagarray[1] = vtx[i ^ 2];
        tagarray[2] = vtx[i ^ 1];
      } else {
        /* `vtx[i]' stores a new link ring containing three tetrahedra.     */
        vtxowner = vtx[i];
        vtxowned = newvertex;
        tagarray[0] = vtx[i ^ 1];
        tagarray[1] = vtx[i ^ 2];
        tagarray[2] = vtx[i ^ 3];
      }

      /* Create the new link ring for edge (vtxowner, vtxowned), using the */
      /*   same allocation index that was used to allocate `vtxowner'.     */
      if (plex->vertexpool == (struct proxipool *) NULL) {
        allocindex = 0;
      } else {
        allocindex = proxipooltag2allocindex(plex->vertexpool, vtxowner);
      }
      ring = linkringnewfill(&plex->moleculepool, vtxowner, tagarray,
                             (proxipoolulong) 3, allocindex);
      /* Make sure `vtxowner' has a 2D link, and find it. */
      star = tetcomplexlookup3dstar(plex, vtxowner);
      /* Store the link ring in 'vtxowner's 2D link. */
      link2dinsertvertex(&plex->moleculepool, plex->cache, star->linkhead,
                         &star->linktail, vtxowner, vtxowned, ring);
    }
  }

  if (newvertex == GHOSTVERTEX) {
    /* The flip replaces one solid tetrahedron with four ghost tetrahedra. */
    plex->tetcount--;
    plex->ghosttetcount += 4;
  } else if ((vtx1 == GHOSTVERTEX) || (vtx2 == GHOSTVERTEX) ||
             (vtx3 == GHOSTVERTEX) || (vtx4 == GHOSTVERTEX)) {
    /* The flip replaces one ghost tetrahedron with one solid tetrahedron */
    /*   and three ghost tetrahedra.                                      */
    plex->tetcount++;
    plex->ghosttetcount += 2;
  } else {
    /* The flip replaces one solid tetrahedron with four. */
    plex->tetcount += 3;
  }

  /*^^^ Assertion:  The tetrahedral complex is now consistent. */
#ifdef PARANOID
  tetcomplexconsistency(plex);
#endif /* PARANOID */
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplex23flip()   Replace two tetrahedra with three (bistellar flip). */
/*                                                                           */
/*  The tetrahedra (vtxtop, vtx1, vtx2, vtx3) and (vtx1, vtx2, vtx3, vtxbot) */
/*  are replaced by the tetrahedra (vtx1, vtx2, vtxtop, vtxbot),             */
/*  (vtx2, vtx3, vtxtop, vtxbot), and (vtx3, vtx1, vtxtop, vtxbot).  This    */
/*  creates one new edge, (vtxtop, vtxbot).  It also deletes one triangle,   */
/*  (vtx1, vtx2, vtx3), and replaces it with three new triangles, all        */
/*  adjoining the new edge.                                                  */
/*                                                                           */
/*  This procedure is equivalent to                                          */
/*                                                                           */
/*    tetcomplexdeletetet(plex, vtxtop, vtx1, vtx2, vtx3);                   */
/*    tetcomplexdeletetet(plex, vtx1, vtx2, vtx3, vtxbot);                   */
/*    tetcomplexinserttet(plex, vtxtop, vtx1, vtx2, vtxbot);                 */
/*    tetcomplexinserttet(plex, vtxtop, vtx2, vtx3, vtxbot);                 */
/*    tetcomplexinserttet(plex, vtxtop, vtx3, vtx1, vtxbot);                 */
/*                                                                           */
/*  only faster, and with less error checking.                               */
/*                                                                           */
/*  This procedure is the inverse of tetcomplex32flip().                     */
/*                                                                           */
/*  WARNING:  This procedure does not check whether the complex actually     */
/*  contains either of the tetrahedra to be deleted, and may fail            */
/*  catastrophically if it does not.                                         */
/*                                                                           */
/*  plex:  The tetcomplex containing the original tetrahedra.                */
/*  vtx1, vtx2, vtx3:  The tags for the vertices of the deleted triangle.    */
/*  vtxbot, vtxtop:  The tags for the vertices of the newly created edge.    */
/*                                                                           */
/*****************************************************************************/

void tetcomplex23flip(struct tetcomplex *plex,
                      tag vtxtop,
                      tag vtx1,
                      tag vtx2,
                      tag vtx3,
                      tag vtxbot)
{
  tag tagarray[3];
  struct tetcomplexstar *star;
  proxipoolulong allocindex;
  tag vtxowner, vtxowned;
  tag ring;

  if (plex->verbosity > 2) {
    printf("      Transforming two tetrahedra to three.\n");
    if (plex->verbosity > 3) {
      printf("        Tags %lu %lu %lu / %lu %lu.\n",
             (unsigned long) vtx1, (unsigned long) vtx2, (unsigned long) vtx3,
             (unsigned long) vtxbot, (unsigned long) vtxtop);
    }
  }

#ifdef SELF_CHECK
  if ((vtx1 == vtx2) || (vtx2 == vtx3) || (vtx3 == vtx1) ||
      (vtx1 == vtxbot) || (vtx2 == vtxbot) || (vtx3 == vtxbot) ||
      (vtx1 == vtxtop) || (vtx2 == vtxtop) || (vtx3 == vtxtop) ||
      (vtxbot == vtxtop)) {
    printf("Internal error in tetcomplex23flip():\n");
    printf("  Asked to perform a flip with two identical vertices.\n");
    internalerror();
  }
#endif /* SELF_CHECK */

  /* Delete the triangle (vtx1, vtx2, vtx3) from the stars of all three */
  /*   of its edges.                                                    */
  tetcomplex21fliponedge(plex, vtx1, vtx2, vtx3);
  tetcomplex21fliponedge(plex, vtx2, vtx3, vtx1);
  tetcomplex21fliponedge(plex, vtx3, vtx1, vtx2);

  /* Insert the triangles (vtxtop, vtx1, vtxbot), (vtxtop, vtx2, vtxbot),  */
  /*   (vtxtop, vtx3, vtxbot) into the stars of their edges, excepting the */
  /*   edge (vtxtop, vtxbot), which we must create anew.                   */
  tetcomplex12fliponedge(plex, vtxtop, vtx1, vtx2, vtx3, vtxbot);
  tetcomplex12fliponedge(plex, vtxtop, vtx2, vtx3, vtx1, vtxbot);
  tetcomplex12fliponedge(plex, vtxtop, vtx3, vtx1, vtx2, vtxbot);
  tetcomplex12fliponedge(plex, vtxbot, vtx1, vtx3, vtx2, vtxtop);
  tetcomplex12fliponedge(plex, vtxbot, vtx2, vtx1, vtx3, vtxtop);
  tetcomplex12fliponedge(plex, vtxbot, vtx3, vtx2, vtx1, vtxtop);

  /* Does the edge (vtxtop, vtxbot) store a link ring?  (Parity check.) */
  if ((vtxtop & 1) == (vtxbot & 1)) {
    /* Yes.  Which of the two vertices is responsible for storing it? */
    if ((vtxbot == GHOSTVERTEX) ||
        ((vtxtop != GHOSTVERTEX) &&
         ((vtxtop < vtxbot) ^ ((vtxtop & 2) == (vtxbot & 2))))) {
      /* `vtxtop' stores a new link ring containing three new tetrahedra. */
      vtxowner = vtxtop;
      vtxowned = vtxbot;
      tagarray[0] = vtx1;
      tagarray[1] = vtx2;
      tagarray[2] = vtx3;
    } else {
      /* `vtxbot' stores a new link ring containing three new tetrahedra. */
      vtxowner = vtxbot;
      vtxowned = vtxtop;
      tagarray[0] = vtx3;
      tagarray[1] = vtx2;
      tagarray[2] = vtx1;
    }

    /* Create the new link ring for edge (vtxowner, vtxowned), using the */
    /*   same allocation index that was used to allocate `vtxowner'.     */
    if (plex->vertexpool == (struct proxipool *) NULL) {
      allocindex = 0;
    } else {
      allocindex = proxipooltag2allocindex(plex->vertexpool, vtxowner);
    }
    ring = linkringnewfill(&plex->moleculepool, vtxowner, tagarray,
                           (proxipoolulong) 3, allocindex);
    /* Make sure `vtxowner' has a 2D link, and find it. */
    star = tetcomplexlookup3dstar(plex, vtxowner);
    /* Store the link ring in 'vtxowner's 2D link. */
    link2dinsertvertex(&plex->moleculepool, plex->cache, star->linkhead,
                       &star->linktail, vtxowner, vtxowned, ring);
  }

  if ((vtxtop == GHOSTVERTEX) || (vtxbot == GHOSTVERTEX)) {
    /* The flip replaces one solid tetrahedron and one ghost tetrahedron */
    /*   with three ghost tetrahedra.                                    */
    plex->tetcount--;
    plex->ghosttetcount += 2;
  } else {
    /* Either the flip replaces two solid tetrahedra with three, or it     */
    /*   replaces two ghost tetrahedra with two different ghost tetrahedra */
    /*   and one solid tetrahedron.                                        */
    plex->tetcount++;
  }

  /*^^^ Assertion:  The tetrahedral complex is now consistent. */
#ifdef PARANOID
  tetcomplexconsistency(plex);
#endif /* PARANOID */
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplex32flip()   Replace three tetrahedra with two (bistellar flip). */
/*                                                                           */
/*  The tetrahedra (vtx1, vtx2, vtxtop, vtxbot), (vtx2, vtx3, vtxtop,        */
/*  vtxbot), and (vtx3, vtx1, vtxtop, vtxbot) are replaced by the tetrahedra */
/*  (vtxtop, vtx1, vtx2, vtx3) and (vtx1, vtx2, vtx3, vtxbot).  This deletes */
/*  one edge, (vtxtop, vtxbot).  It also deletes three triangles adjoining   */
/*  that edge, and replaces them with a new triangle, (vtx1, vtx2, vtx3).    */
/*                                                                           */
/*  This procedure is equivalent to                                          */
/*                                                                           */
/*    tetcomplexdeletetet(plex, vtxtop, vtx1, vtx2, vtxbot);                 */
/*    tetcomplexdeletetet(plex, vtxtop, vtx2, vtx3, vtxbot);                 */
/*    tetcomplexdeletetet(plex, vtxtop, vtx3, vtx1, vtxbot);                 */
/*    tetcomplexinserttet(plex, vtxtop, vtx1, vtx2, vtx3);                   */
/*    tetcomplexinserttet(plex, vtx1, vtx2, vtx3, vtxbot);                   */
/*                                                                           */
/*  only faster, and with less error checking.                               */
/*                                                                           */
/*  This procedure is the inverse of tetcomplex23flip().                     */
/*                                                                           */
/*  WARNING:  This procedure does not check whether the complex actually     */
/*  contains any of the tetrahedra to be deleted, and may fail               */
/*  catastrophically if it does not.                                         */
/*                                                                           */
/*  plex:  The tetcomplex containing the original tetrahedra.                */
/*  vtx1, vtx2, vtx3:  The tags for the vertices of the new triangle.        */
/*  vtxbot, vtxtop:  The tags for the vertices of the deleted edge.          */
/*                                                                           */
/*****************************************************************************/

void tetcomplex32flip(struct tetcomplex *plex,
                      tag vtxtop,
                      tag vtx1,
                      tag vtx2,
                      tag vtx3,
                      tag vtxbot)
{
  struct tetcomplexstar *star;
  tag ring;

  if (plex->verbosity > 2) {
    printf("      Transforming three tetrahedra to two.\n");
    if (plex->verbosity > 3) {
      printf("        Tags %lu %lu %lu / %lu %lu.\n",
             (unsigned long) vtx1, (unsigned long) vtx2, (unsigned long) vtx3,
             (unsigned long) vtxbot, (unsigned long) vtxtop);
    }
  }

#ifdef SELF_CHECK
  if ((vtx1 == vtx2) || (vtx2 == vtx3) || (vtx3 == vtx1) ||
      (vtx1 == vtxbot) || (vtx2 == vtxbot) || (vtx3 == vtxbot) ||
      (vtx1 == vtxtop) || (vtx2 == vtxtop) || (vtx3 == vtxtop) ||
      (vtxbot == vtxtop)) {
    printf("Internal error in tetcomplex32flip():\n");
    printf("  Asked to perform a flip with two identical vertices.\n");
    internalerror();
  }
#endif /* SELF_CHECK */

  /* Delete the triangles (vtxtop, vtx1, vtxbot), (vtxtop, vtx2, vtxbot),  */
  /*   (vtxtop, vtx3, vtxbot) from the stars of their edges, excepting the */
  /*   edge (vtxtop, vtxbot), which we shall delete in one blow.           */
  tetcomplex21fliponedge(plex, vtxtop, vtx1, vtxbot);
  tetcomplex21fliponedge(plex, vtxtop, vtx2, vtxbot);
  tetcomplex21fliponedge(plex, vtxtop, vtx3, vtxbot);
  tetcomplex21fliponedge(plex, vtxbot, vtx1, vtxtop);
  tetcomplex21fliponedge(plex, vtxbot, vtx2, vtxtop);
  tetcomplex21fliponedge(plex, vtxbot, vtx3, vtxtop);

  /* Insert the triangle (vtx1, vtx2, vtx3) into the stars of all three */
  /*   of its edges.                                                    */
  tetcomplex12fliponedge(plex, vtx1, vtx2, vtxtop, vtxbot, vtx3);
  tetcomplex12fliponedge(plex, vtx2, vtx3, vtxtop, vtxbot, vtx1);
  tetcomplex12fliponedge(plex, vtx3, vtx1, vtxtop, vtxbot, vtx2);

  /* Does the edge (vtxtop, vtxbot) store a link ring?  (Parity check.) */
  if ((vtxtop & 1) == (vtxbot & 1)) {
    /* Yes.  Which of the two vertices is responsible for storing it? */
    if ((vtxbot == GHOSTVERTEX) ||
        ((vtxtop != GHOSTVERTEX) &&
         ((vtxtop < vtxbot) ^ ((vtxtop & 2) == (vtxbot & 2))))) {
      if (vtxtop >= plex->nextinitindex) {
        printf("Internal error in tetcomplex32flip():\n");
        printf("  Central edge (to be deleted by a 3-2 flip) is missing.\n");
        internalerror();
      }

      /* Delete edge (vtxtop, vtxbot) and its link ring from `vtxtop's star. */
      star = (struct tetcomplexstar *)
             arraypoolfastlookup(&plex->stars, (arraypoolulong) vtxtop);
      ring = link2ddeletevertex(&plex->moleculepool, plex->cache,
                                star->linkhead, &star->linktail,
                                vtxtop, vtxbot);
    } else {
      if (vtxbot >= plex->nextinitindex) {
        printf("Internal error in tetcomplex32flip():\n");
        printf("  Central edge (to be deleted by a 3-2 flip) is missing.\n");
        internalerror();
      }

      /* Delete edge (vtxtop, vtxbot) and its link ring from `vtxbot's star. */
      star = (struct tetcomplexstar *)
             arraypoolfastlookup(&plex->stars, (arraypoolulong) vtxbot);
      ring = link2ddeletevertex(&plex->moleculepool, plex->cache,
                                star->linkhead, &star->linktail,
                                vtxbot, vtxtop);
    }
    if (ring == STOP) {
      printf("Internal error in tetcomplex32flip():\n");
      printf("  Central edge (to be deleted by a 3-2 flip) is missing.\n");
      internalerror();
    } else {
      linkringdelete(&plex->moleculepool, ring);
    }
  }

  if ((vtxtop == GHOSTVERTEX) || (vtxbot == GHOSTVERTEX)) {
    /* The flip replaces three ghost tetrahedra with one solid tetrahedron */
    /*   and one ghost tetrahedron.                                        */
    plex->tetcount++;
    plex->ghosttetcount -= 2;
  } else {
    /* Either the flip replaces three solid tetrahedra with two, or it    */
    /*   replaces two ghost tetrahedra and one solid tetrahedron with two */
    /*   different ghost tetrahedra.                                      */
    plex->tetcount--;
  }

  /*^^^ Assertion:  The tetrahedral complex is now consistent. */
#ifdef PARANOID
  tetcomplexconsistency(plex);
#endif /* PARANOID */
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplex41flip()   Replace four tetrahedra with one (bistellar flip).  */
/*                                                                           */
/*  The tetrahedra (newvertex, vtx2, vtx3, vtx4), (vtx1, newvertex, vtx3,    */
/*  vtx4), (vtx1, vtx2, newvertex, vtx4), and (vtx1, vtx2, vtx3, newvertex)  */
/*  are replaced by the tetrahedron (vtx1, vtx2, vtx3, vtx4).  Equivalently, */
/*  `deletevertex' is deleted from inside a tetrahedron.                     */
/*                                                                           */
/*  This procedure is equivalent to                                          */
/*                                                                           */
/*    tetcomplexinserttet(plex, deletevertex, vtx2, vtx3, vtx4);             */
/*    tetcomplexinserttet(plex, vtx1, deletevertex, vtx3, vtx4);             */
/*    tetcomplexinserttet(plex, vtx1, vtx2, deletevertex, vtx4);             */
/*    tetcomplexinserttet(plex, vtx1, vtx2, vtx3, deletevertex);             */
/*    tetcomplexdeletetet(plex, vtx1, vtx2, vtx3, vtx4);                     */
/*                                                                           */
/*  only faster, and with less error checking.                               */
/*                                                                           */
/*  This procedure is the inverse of tetcomplex14flip().                     */
/*                                                                           */
/*  WARNING:  This procedure does not check whether the complex actually     */
/*  contains any of the tetrahedra to be deleted, and may fail               */
/*  catastrophically if it does not.                                         */
/*                                                                           */
/*  plex:  The tetcomplex containing the original tetrahedra.                */
/*  vtx1, vtx2, vtx3, vtx4:  The tags for the vertices of the tetrahedron    */
/*    created by the flip.                                                   */
/*  deletevertex:  The tag for the vertex to delete.                         */
/*                                                                           */
/*****************************************************************************/

void tetcomplex41flip(struct tetcomplex *plex,
                      tag vtx1,
                      tag vtx2,
                      tag vtx3,
                      tag vtx4,
                      tag deletevertex)
{
  struct tetcomplexstar *star;
  tag ring;
  tag vtxi;
  int i;

  if (plex->verbosity > 2) {
    printf("      Transforming four tetrahedra to one (vertex deletion).\n");
    if (plex->verbosity > 3) {
      printf("        Tags %lu %lu %lu %lu; deleted vertex tag %lu.\n",
             (unsigned long) vtx1, (unsigned long) vtx2, (unsigned long) vtx3,
             (unsigned long) vtx4, (unsigned long) deletevertex);
    }
  }

#ifdef SELF_CHECK
  if ((deletevertex == vtx1) || (deletevertex == vtx2) ||
      (deletevertex == vtx3) || (deletevertex == vtx4) ||
      (vtx1 == vtx2) || (vtx1 == vtx3) || (vtx1 == vtx4) ||
      (vtx2 == vtx3) || (vtx2 == vtx4) || (vtx3 == vtx4)) {
    printf("Internal error in tetcomplex41flip():\n");
    printf("  Asked to perform a flip with two identical vertices.\n");
    internalerror();
  }
#endif /* SELF_CHECK */

  /* Delete the triangles adjoining `deletevertex' from the stars of the */
  /*   surviving edges.                                                  */
  tetcomplex21fliponedge(plex, vtx1, vtx2, deletevertex);
  tetcomplex21fliponedge(plex, vtx1, vtx3, deletevertex);
  tetcomplex21fliponedge(plex, vtx1, vtx4, deletevertex);
  tetcomplex21fliponedge(plex, vtx2, vtx3, deletevertex);
  tetcomplex21fliponedge(plex, vtx2, vtx4, deletevertex);
  tetcomplex21fliponedge(plex, vtx3, vtx4, deletevertex);

  /* Delete the four edges adjoining `deletevertex' and their link rings. */
  for (i = 1; i <= 4; i++) {
    vtxi = (i <= 2) ? ((i == 1) ? vtx1 : vtx2) : ((i == 3) ? vtx3 : vtx4);
    /* Does the edge (newvertex, vtxi) store a link ring?  (Parity check.) */
    if ((deletevertex & 1) == (vtxi & 1)) {
      /* Yes.  Which of the two vertices is responsible for storing it? */
      ring = STOP;
      if ((vtxi == GHOSTVERTEX) ||
          ((deletevertex != GHOSTVERTEX) &&
           ((deletevertex < vtxi) ^ ((deletevertex & 2) == (vtxi & 2))))) {
        /* `deletevertex' stores the link ring.  Delete the ring. */
        if (deletevertex < plex->nextinitindex) {
          star = (struct tetcomplexstar *)
                 arraypoolfastlookup(&plex->stars,
                                     (arraypoolulong) deletevertex);
          ring = link2ddeletevertex(&plex->moleculepool, plex->cache,
                                    star->linkhead, &star->linktail,
                                    deletevertex, vtxi);
        }
      } else {
        /* `vtxi' stores the link ring.  Delete the ring. */
        if (vtxi < plex->nextinitindex) {
          star = (struct tetcomplexstar *)
                 arraypoolfastlookup(&plex->stars, (arraypoolulong) vtxi);
          ring = link2ddeletevertex(&plex->moleculepool, plex->cache,
                                    star->linkhead, &star->linktail,
                                    vtxi, deletevertex);
        }
      }

      if (ring == STOP) {
        printf("Internal error in tetcomplex41flip():\n");
        printf("  An edge to be deleted by a 4-1 flip is missing.\n");
        internalerror();
      } else {
        linkringdelete(&plex->moleculepool, ring);
      }
    }
  }

  if (deletevertex == GHOSTVERTEX) {
    /* The flip replaces four ghost tetrahedra with one solid tetrahedron. */
    plex->tetcount++;
    plex->ghosttetcount -= 4;
  } else if ((vtx1 == GHOSTVERTEX) || (vtx2 == GHOSTVERTEX) ||
             (vtx3 == GHOSTVERTEX) || (vtx4 == GHOSTVERTEX)) {
    /* The flip replaces one solid tetrahedron and three ghost tetrahedra */
    /*   with one ghost tetrahedron.                                      */
    plex->tetcount--;
    plex->ghosttetcount -= 2;
  } else {
    /* The flip replaces four solid tetrahedra with one. */
    plex->tetcount -= 3;
  }

  /*^^^ Assertion:  The tetrahedral complex is now consistent. */
#ifdef PARANOID
  tetcomplexconsistency(plex);
#endif /* PARANOID */
}

void tetcomplexbuild3dstar(struct tetcomplex *plex,
                           tag newvertex,
                           struct arraypool *trianglelist,
                           arraypoolulong firstindex,
                           arraypoolulong trianglecount)
{
  struct tetcomplexstar *star;
  struct tetcomplexlinktriangle *triangle, *traveltri;
  tag tagarray[512];
  tag origin;
  tag vtx1, vtx2;
  tag ring;
  proxipoolulong allocindex;
  proxipoolulong tagindex;
  proxipoolulong i;
  arraypoolulong triindex;
  arraypoolulong travelindex;
  arraypoolulong orgneighbor;
  int edge;
  int traveledge;

  for (triindex = firstindex; triindex < firstindex + trianglecount;
       triindex++) {
    triangle = (struct tetcomplexlinktriangle *)
               arraypoolfastlookup(trianglelist, triindex);
    for (edge = 0; edge < 3; edge++) {
      origin = triangle->vtx[(edge == 2) ? 0 : edge + 1];
      if ((origin & 1) == (newvertex & 1)) {
        orgneighbor = triangle->neighbor[edge];
        if (orgneighbor < ~orgneighbor) {
          if ((origin == GHOSTVERTEX) ||
              ((newvertex != GHOSTVERTEX) &&
               ((newvertex < origin) ^ ((newvertex & 2) == (origin & 2))))) {
            vtx1 = newvertex;
            vtx2 = origin;
          } else {
            vtx1 = origin;
            vtx2 = newvertex;
          }

          tagindex = 0;
          traveledge = edge;
          traveltri = triangle;
          do {
            tagarray[tagindex] = traveltri->vtx[traveledge];
            tagindex++;
            if (vtx1 == newvertex) {
              traveltri->neighbor[traveledge] =
                ~traveltri->neighbor[traveledge];
              travelindex = traveltri->neighbor[(traveledge == 0) ?
                                                2 : traveledge - 1];
              travelindex = (travelindex < ~travelindex) ?
                            travelindex : ~travelindex;
              traveledge = travelindex & 3;
            } else {
              travelindex = traveltri->neighbor[traveledge];
              traveltri->neighbor[traveledge] = ~travelindex;
              traveledge = travelindex & 3;
              traveledge = (traveledge == 2) ? 0 : traveledge + 1;
            }
            traveltri = (struct tetcomplexlinktriangle *)
                        arraypoolfastlookup(trianglelist, travelindex >> 2);
          } while (traveltri != triangle);

          if (plex->verbosity > 3) {
            printf("        Creating link ring for edge w/tags %lu %lu:\n"
                   "         ",
                   (unsigned long) vtx1, (unsigned long) vtx2);
            for (i = 0; i < tagindex; i++) {
              printf(" %lu", (unsigned long) tagarray[i]);
            }
            printf("\n");
          }

          /* Create the new link ring for edge (vtx1, vtx2), using the */
          /*   same allocation index that was used to allocate `vtx1'. */
          if (plex->vertexpool == (struct proxipool *) NULL) {
            allocindex = 0;
          } else {
            allocindex = proxipooltag2allocindex(plex->vertexpool, vtx1);
          }
          ring = linkringnewfill(&plex->moleculepool, vtx1, tagarray,
                                 tagindex, allocindex);
          /* Make sure `vtx1' has a 2D star, and find it. */
          star = tetcomplexlookup3dstar(plex, vtx1);
          /* Store the link ring in 'vtx1's 2D link. */
          link2dinsertvertex(&plex->moleculepool, plex->cache, star->linkhead,
                             &star->linktail, vtx1, vtx2, ring);
        }

        triangle->neighbor[edge] = ~orgneighbor;
      }
    }

    if ((triangle->vtx[0] == GHOSTVERTEX) ||
        (triangle->vtx[1] == GHOSTVERTEX) ||
        (triangle->vtx[2] == GHOSTVERTEX)) {
      plex->ghosttetcount++;
    } else {
      plex->tetcount++;
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexremoveghosttets()   Deletes all ghost edges, and their stars,  */
/*                                from a tetcomplex, thereby deleting all    */
/*                                the explicitly inserted ghost tetrahedra.  */
/*                                                                           */
/*  This procedure searches the star of every vertex, rather than trying to  */
/*  do something more clever like finding one ghost tetrahedron by           */
/*  exhaustive search, then the others by walking through all the ghost      */
/*  triangles.  The advantage is that it will work correctly no matter how   */
/*  inconsistent the stars are with each other.  The disadvantage is that    */
/*  it's not as fast as it would be if implemented the clever way.           */
/*                                                                           */
/*  plex:  The tetcomplex in question.                                       */
/*                                                                           */
/*****************************************************************************/

void tetcomplexremoveghosttets(struct tetcomplex *plex)
{
  struct tetcomplexstar *newstar;
  tag starvertex;
  tag ghostring;

  if (plex->verbosity) {
    printf("  Removing ghost tetrahedra.\n");
  }

  /* Loop through all the vertices that might exist. */
  for (starvertex = 0; starvertex < plex->nextinitindex; starvertex++) {
    /* Is there a star for a vertex with tag `starvertex'? */
    newstar = (struct tetcomplexstar *)
      arraypoolfastlookup(&plex->stars, (arraypoolulong) starvertex);
    if (newstar->linkhead != STOP) {
      /* Remove the GHOSTVERTEX (and its link ring), if it is present, */
      /*   from the star of `starvertex'.                              */
      ghostring = link2ddeletevertex(&plex->moleculepool, plex->cache, 
                                     newstar->linkhead, &newstar->linktail,
                                     starvertex, GHOSTVERTEX);
      if (ghostring != STOP) {
        /* Deallocate the link ring. */
        linkringdelete(&plex->moleculepool, ghostring);
      }
    }
  }

  plex->ghosttetcount = 0;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplextetcount()   Returns the number of solid tetrahedra a          */
/*                         tetcomplex believes it contains.                  */
/*                                                                           */
/*  Ghost tetrahedra have no effect on the return value.                     */
/*                                                                           */
/*  The return value is meaningless if the tetcomplex is not internally      */
/*  consistent (as during a run of the star splaying algorithm).             */
/*                                                                           */
/*  The return value may be wrong if the tetcomplex passed through a state   */
/*  where it was not internally consistent, and the count has not been       */
/*  refreshed since the tetcomplex became consistent again.                  */
/*                                                                           */
/*  plex:  The tetcomplex in question.                                       */
/*                                                                           */
/*  Returns the number of solid tetrahedra believed to be in the complex.    */
/*                                                                           */
/*****************************************************************************/

arraypoolulong tetcomplextetcount(struct tetcomplex *plex)
{
  return plex->tetcount;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexghosttetcount()   Returns the number of _explicitly_inserted_  */
/*                              ghost tetrahedra a tetcomplex believes it    */
/*                              "contains".                                  */
/*                                                                           */
/*  Returns the value of an internal counter that is incremented with every  */
/*  successful explicit insertion of a ghost tetrahedron, and decremented    */
/*  with every successful explicit deletion of a ghost tetrahedron.  The     */
/*  explicit insertion or deletion of a ghost tetrahedron does not always    */
/*  change the tetcomplex data structure at all (because the GHOSTVERTEX     */
/*  might have a parity opposite to that of the other three vertices), so    */
/*  this number doesn't reflect any measurable property of the data          */
/*  structure.  The count is easily fooled, because you can repeatedly and   */
/*  "successfully" insert or delete a ghost tetrahedron that doesn't change  */
/*  the data structure.  Nevertheless, if ghost tetrahedra are inserted and  */
/*  deleted in a disciplined way, this count is the number of triangles on   */
/*  the boundary of the triangulation, and that is how the Bowyer-Watson     */
/*  implementation uses it.                                                  */
/*                                                                           */
/*  The return value is meaningless if the tetcomplex is not internally      */
/*  consistent (as it is not during a run of the star splaying algorithm).   */
/*                                                                           */
/*  The return value may be wrong if the tetcomplex passed through a state   */
/*  where it was not internally consistent, and the count has not been       */
/*  refreshed since the tetcomplex became consistent again.                  */
/*                                                                           */
/*  plex:  The tetcomplex in question.                                       */
/*                                                                           */
/*  Returns the number of ghost tetrahedra believed to be in the complex.    */
/*                                                                           */
/*****************************************************************************/

arraypoolulong tetcomplexghosttetcount(struct tetcomplex *plex)
{
  return plex->ghosttetcount;
}

/*****************************************************************************/
/*                                                                           */
/*  tetcomplexbytes()   Returns the number of bytes of dynamic memory used   */
/*                      by the tetrahedral complex.                          */
/*                                                                           */
/*  Does not include the memory for the `struct tetcomplex' record itself.   */
/*                                                                           */
/*  plex:  The tetcomplex in question.                                       */
/*                                                                           */
/*  Returns the number of dynamically allocated bytes in `plex'.             */
/*                                                                           */
/*****************************************************************************/

arraypoolulong tetcomplexbytes(struct tetcomplex *plex)
{
  return proxipoolbytes(&plex->moleculepool) +
         arraypoolbytes(&plex->stars);
}

/**                                                                         **/
/**                                                                         **/
/********* Tetrahedral complex routines end here                     *********/


/********* Input routines begin here                                 *********/
/**                                                                         **/
/**                                                                         **/

/*  A vertex is assigned the `number' DEADVERTEX when it is deallocated, to  */
/*  indicate that the vertex record should not be consulted (and its memory  */
/*  might be reclaimed by another vertex any time).  A vertex is most likely */
/*  to become dead if it is a non-corner node of an input mesh (such as the  */
/*  side-edge nodes of a quadratic element), or if it was generated (not an  */
/*  input vertex) then subsequently deleted from a mesh.                     */
/*                                                                           */
/*  A vertex is assigned the `number' ACTIVEVERTEX temporarily when the      */
/*  `jettison' (-j) switch is used, to indicate that some tetrahedron has it */
/*  for a vertex and it should not be discarded.                             */

#define DEADVERTEX ((arraypoolulong) ~0)
#define ACTIVEVERTEX ((arraypoolulong) ~1)

/*  `vertexmarktype' is the type of int for the user-specified marker        */
/*  associated with each vertex.  These markers are typically used to keep   */
/*  track of which vertices lie on which segments or facets, and which       */
/*  boundary conditions should be applied to which vertices.                 */

typedef int vertexmarktype;


/*  A `vertex' is a structure that represents a vertex in the mesh.  Each    */
/*  vertex has three coordinates (x, y, and z) in `coord', a vertex mark     */
/*  stored in `mark', and a `number' by which the user indexes the vertex.   */
/*  Note that a vertex may have a different number in the output files than  */
/*  it had in the input files.  Note that each vertex may have auxiliary     */
/*  user-provided floating-point attributes, but these are not stored        */
/*  contiguously with the vertex structures.                                 */

struct vertex {
  starreal coord[3];
  vertexmarktype mark;
  arraypoolulong number;
};

/*  A `vertexshort' is a structure that represents a vertex in the mesh.     */
/*  It is like a `vertex', but the vertex number is omitted to save space.   */
/*  The `coord' array comes last because it is treated as a variable-length  */
/*  array, with indices 3 and greater representing user-provided floating-   */
/*  point attributes.  This structure is typically used for vertex sorting   */
/*  prior to triangulation.                                                  */

struct vertexshort {
  vertexmarktype mark;
  starreal coord[3];
};

struct inputs {
  tag *vertextags;
  arraypoolulong vertexcount;                   /* Number of input vertices. */
  unsigned int attribcount;              /* Number of attributes per vertex. */
  arraypoolulong firstnumber;   /* Vertices are numbered starting from this. */
  arraypoolulong deadvertexcount;     /* Non-corner input vertices (killed). */
  arraypoolulong tetcount;                    /* Number of input tetrahedra. */
  unsigned int tetattribcount;      /* Number of attributes per tetrahedron. */
  arraypoolulong segmentcount;                  /* Number of input segments. */
  arraypoolulong facetcount;                      /* Number of input facets. */
  arraypoolulong holecount;                        /* Number of input holes. */
  arraypoolulong regioncount;                    /* Number of input regions. */
};

struct outputs {
  arraypoolulong vertexcount;
  arraypoolulong tetcount;
  arraypoolulong facecount;
  arraypoolulong boundaryfacecount;
  arraypoolulong edgecount;
};


void vertexcheckorientation(struct behavior *behave,
                            struct tetcomplex *plex,
                            tag vtx1,
                            tag vtx2,
                            tag vtx3,
                            tag vtx4)
{
  starreal ori;
  struct vertex *point1;
  struct vertex *point2;
  struct vertex *point3;
  struct vertex *point4;

  point1 = (struct vertex *) tetcomplextag2vertex(plex, vtx1);
  point2 = (struct vertex *) tetcomplextag2vertex(plex, vtx2);
  point3 = (struct vertex *) tetcomplextag2vertex(plex, vtx3);
  point4 = (struct vertex *) tetcomplextag2vertex(plex, vtx4);

  ori = orient3d(behave, point1->coord, point2->coord, point3->coord,
                 point4->coord);
  if (ori <= 0.0) {
    if (ori < 0.0) {
      printf("  !! !! Creating inverted tet\n");
    } else {
      printf("  !! !! Creating degenerate tet\n");
    }
    printf("        # %lu tag %lu (%.12g, %.12g, %.12g)"
           " # %lu tag %lu (%.12g, %.12g, %.12g)\n",
           (unsigned long) point1->number, (unsigned long) vtx1,
           (double) point1->coord[0], (double) point1->coord[1],
           (double) point1->coord[2],
           (unsigned long) point2->number, (unsigned long) vtx2,
           (double) point2->coord[0], (double) point2->coord[1],
           (double) point2->coord[2]);
    printf("        # %lu tag %lu (%.12g, %.12g, %.12g)"
           " # %lu tag %lu (%.12g, %.12g, %.12g)\n",
           (unsigned long) point3->number, (unsigned long) vtx3,
           (double) point3->coord[0], (double) point3->coord[1],
           (double) point3->coord[2],
           (unsigned long) point4->number, (unsigned long) vtx4,
           (double) point4->coord[0], (double) point4->coord[1],
           (double) point4->coord[2]);
  }
}

/*****************************************************************************/
/*                                                                           */
/*  inputtextline()   Read a nonempty line from a file.                      */
/*                                                                           */
/*  A line is considered "nonempty" if it contains something that looks like */
/*  a number.  Comments (prefaced by `#') are ignored.                       */
/*                                                                           */
/*****************************************************************************/

#ifndef STARLIBRARY

char *inputtextline(char *string,
                    FILE *infile,
                    char *infilename)
{
  char *result;

  /* Search for something that looks like a number. */
  do {
    result = fgets(string, INPUTLINESIZE, infile);
    if (result == (char *) NULL) {
      printf("  Error:  Unexpected end of file in %s.\n", infilename);
      starexit(1);
    }

    /* Skip anything that doesn't look like a number, a comment, */
    /*   or the end of a line.                                   */
    while ((*result != '\0') && (*result != '#') &&
           (*result != '.') && (*result != '+') && (*result != '-') &&
           ((*result < '0') || (*result > '9'))) {
      result++;
    }
  /* If it's a comment or end of line, read another line and try again. */
  } while ((*result == '#') || (*result == '\0'));

  return result;
}

#endif /* not STARLIBRARY */

/*****************************************************************************/
/*                                                                           */
/*  inputfindfield()   Find the next field of a string.                      */
/*                                                                           */
/*  Jumps past the current field by searching for whitespace, then jumps     */
/*  past the whitespace to find the next field.                              */
/*                                                                           */
/*****************************************************************************/

#ifndef STARLIBRARY

char *inputfindfield(char *string)
{
  char *result;

  result = string;
  /* Skip the current field.  Stop upon reaching whitespace. */
  while ((*result != '\0') && (*result != '#') &&
         (*result != ' ') && (*result != '\t')) {
    result++;
  }

  /* Now skip the whitespace and anything else that doesn't look like a */
  /*   number, a comment, or the end of a line.                         */
  while ((*result != '\0') && (*result != '#') &&
         (*result != '.') && (*result != '+') && (*result != '-') &&
         ((*result < '0') || (*result > '9'))) {
    result++;
  }

  /* Check for a comment (prefixed with `#'). */
  if (*result == '#') {
    *result = '\0';
  }

  return result;
}

#endif /* not STARLIBRARY */

/*****************************************************************************/
/*                                                                           */
/*  inputvertices()   Read the vertices from a file into a newly created     */
/*                    array, in `struct vertexshort' format.                 */
/*                                                                           */
/*****************************************************************************/

#ifndef STARLIBRARY

char *inputvertices(FILE *vertexfile,
                    char *vertexfilename,
                    struct inputs *in,
                    int markflag)
{
  char inputline[INPUTLINESIZE];
  char *stringptr;
  char *vertices;
  struct vertexshort *vertexptr;
  size_t vertexbytes;
  long firstnode;
  arraypoolulong i;
  unsigned int j;

  vertexbytes = sizeof(struct vertexshort) +
                (size_t) in->attribcount * sizeof(starreal);
  vertices = (char *) starmalloc((size_t) (in->vertexcount * vertexbytes));

  /* Read the vertices. */
  for (i = 0; i < in->vertexcount; i++) {
    vertexptr = (struct vertexshort *) &vertices[i * vertexbytes];

    stringptr = inputtextline(inputline, vertexfile, vertexfilename);
    if (i == 0) {
      firstnode = (long) strtol(stringptr, &stringptr, 0);
      if ((firstnode == 0) || (firstnode == 1)) {
        in->firstnumber = (arraypoolulong) firstnode;
      }
    }

    /* Read the vertex coordinates and attributes. */
    for (j = 0; j < 3 + in->attribcount; j++) {
      stringptr = inputfindfield(stringptr);
      if (*stringptr == '\0') {
        if (j >= 3) {
          vertexptr->coord[j] = 0.0;
        } else {
          printf("Error:  Vertex %lu has no %c coordinate.\n",
                 (unsigned long) (in->firstnumber + i),
                 (j == 0) ? 'x' : (j == 1) ? 'y' : 'z');
          starexit(1);
        }
      } else {
        vertexptr->coord[j] = (starreal) strtod(stringptr, &stringptr);
      }
    }

    if (markflag) {
      /* Read a vertex marker. */
      stringptr = inputfindfield(stringptr);
      if (*stringptr == '\0') {
        vertexptr->mark = 0;
      } else {
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
        vertexptr->mark = (vertexmarktype) strtoll(stringptr, &stringptr, 0);
#else /* no long long type */
        vertexptr->mark = (vertexmarktype) strtol(stringptr, &stringptr, 0);
#endif
      }
    }
  }

  return vertices;
}

#endif /* not STARLIBRARY */

char *inputvertexfile(struct behavior *behave,
                      struct inputs *in,
                      FILE **polyfile)
{
  char inputline[INPUTLINESIZE];
  char *stringptr;
  FILE *infile = (FILE *) NULL;
  char *infilename;
  char *vertices;
  int mesh_dim = 3;
  int markflag = 0;

  if (behave->poly) {
    /* Read the vertices from a .poly file. */
    if (!behave->quiet) {
      printf("Opening %s.\n", behave->inpolyfilename);
    }

    *polyfile = fopen(behave->inpolyfilename, "r");
    if (*polyfile == (FILE *) NULL) {
      printf("  Error:  Cannot access file %s.\n", behave->inpolyfilename);
      starexit(1);
    }

    /* Read number of vertices, number of dimensions, number of vertex */
    /*   attributes, and number of boundary markers.                   */
    stringptr = inputtextline(inputline, *polyfile,
                              behave->inpolyfilename);
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
    in->vertexcount = (arraypoolulong) strtoull(stringptr, &stringptr, 0);
#else /* no long long type */
    in->vertexcount = (arraypoolulong) strtoul(stringptr, &stringptr, 0);
#endif
    stringptr = inputfindfield(stringptr);
    if (*stringptr == '\0') {
      mesh_dim = 3;
    } else {
      mesh_dim = (int) strtol(stringptr, &stringptr, 0);
    }
    stringptr = inputfindfield(stringptr);
    if (*stringptr == '\0') {
      in->attribcount = 0;
    } else {
      in->attribcount = (unsigned int) strtoul(stringptr, &stringptr, 0);
    }
    stringptr = inputfindfield(stringptr);
    if (*stringptr == '\0') {
      markflag = 0;
    } else {
      markflag = (int) strtol(stringptr, &stringptr, 0);
    }

    if (in->vertexcount > 0) {
      infile = *polyfile;
      infilename = behave->inpolyfilename;
      behave->readnodefileflag = 0;
    } else {
      /* If the .poly file claims there are zero vertices, that means that */
      /*   the vertices should be read from a separate .node file.         */
      behave->readnodefileflag = 1;
      infilename = behave->innodefilename;
    }
  } else {
    behave->readnodefileflag = 1;
    infilename = behave->innodefilename;
    *polyfile = (FILE *) NULL;
  }
  in->deadvertexcount = 0;

  if (behave->readnodefileflag) {
    /* Read the vertices from a .node file. */
    if (!behave->quiet) {
      printf("Opening %s.\n", behave->innodefilename);
    }

    infile = fopen(behave->innodefilename, "r");
    if (infile == (FILE *) NULL) {
      printf("  Error:  Cannot access file %s.\n", behave->innodefilename);
      starexit(1);
    }

    /* Read number of vertices, number of dimensions, number of vertex */
    /*   attributes, and number of boundary markers.                   */
    stringptr = inputtextline(inputline, infile, behave->innodefilename);
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
    in->vertexcount = (arraypoolulong) strtoull(stringptr, &stringptr, 0);
#else /* no long long type */
    in->vertexcount = (arraypoolulong) strtoul(stringptr, &stringptr, 0);
#endif
    stringptr = inputfindfield(stringptr);
    if (*stringptr == '\0') {
      mesh_dim = 3;
    } else {
      mesh_dim = (int) strtol(stringptr, &stringptr, 0);
    }
    stringptr = inputfindfield(stringptr);
    if (*stringptr == '\0') {
      in->attribcount = 0;
    } else {
      in->attribcount = (unsigned int) strtoul(stringptr, &stringptr, 0);
    }
    stringptr = inputfindfield(stringptr);
    if (*stringptr == '\0') {
      markflag = 0;
    } else {
      markflag = (int) strtol(stringptr, &stringptr, 0);
    }
  }

  if (in->vertexcount < 4) {
    printf("Error:  Input must have at least four input vertices.\n");
    starexit(1);
  }
  if (mesh_dim != 3) {
    printf("Error:  Star only works with three-dimensional meshes.\n");
    starexit(1);
  }

  in->firstnumber = behave->firstnumber;
  vertices = inputvertices(infile, infilename, in, markflag);

  if (behave->readnodefileflag) {
    fclose(infile);
  }

  behave->firstnumber = in->firstnumber;
  if (in->attribcount == 0) {
    behave->weighted = 0;
  }

  return vertices;
}

/*****************************************************************************/
/*                                                                           */
/*  inputvertexsort()   Sort an array of vertices (in `struct vertexshort'   */
/*                      format) along a z-order space-filling curve.         */
/*                                                                           */
/*  Uses quicksort.  Randomized O(n log n) time.                             */
/*                                                                           */
/*  Sorts whole `struct vertexshort' records, rather than pointers to        */
/*  records, because I think it will be faster for very large vertex sets,   */
/*  where quicksort's linear walk through the array favors the memory        */
/*  hierarchy better than pseudo-random record lookups.                      */
/*                                                                           */
/*****************************************************************************/

void inputvertexsort(char *vertices,
                     tag *vertextags,
                     arraypoolulong vertexcount,
                     size_t vertexbytes,
                     unsigned int attribcount)
{
  struct vertexshort tempvertex;
  struct vertexshort pivotvertex;
  struct vertexshort *leftptr, *rightptr, *pivotptr;
  arraypoolulong leftindex, rightindex, pivotindex;
  starreal pivotx, pivoty, pivotz;
  starreal tempreal;
  tag pivottag;
  tag temptag;
  unsigned int j;

  if (vertexcount == 2) {
    /* Base case of the recursion. */
    leftptr = (struct vertexshort *) vertices;
    rightptr = (struct vertexshort *) &vertices[vertexbytes];
    if (zorderbefore(rightptr->coord[0], rightptr->coord[1],
                     rightptr->coord[2], leftptr->coord[0],
                     leftptr->coord[1], leftptr->coord[2])) {
      temptag = vertextags[1];
      vertextags[1] = vertextags[0];
      vertextags[0] = temptag;
      tempvertex = *rightptr;
      *rightptr = *leftptr;
      *leftptr = tempvertex;
      for (j = 3; j < 3 + attribcount; j++) {
        tempreal = rightptr->coord[j];
        rightptr->coord[j] = leftptr->coord[j];
        leftptr->coord[j] = tempreal;
      }
    }
    return;
  }

  if (vertexcount < 5) {
    pivotindex = 0;
    pivotptr = (struct vertexshort *) vertices;
  } else {
    /* Choose a random pivot to split the array. */
    pivotindex = (arraypoolulong) randomnation((unsigned int) vertexcount);
    pivotptr = (struct vertexshort *) &vertices[pivotindex * vertexbytes];
  }
  pivottag = vertextags[pivotindex];
  pivotvertex = *pivotptr;
  pivotx = pivotvertex.coord[0];
  pivoty = pivotvertex.coord[1];
  pivotz = pivotvertex.coord[2];
  if (pivotindex > 0) {
    /* Move the first vertex of the array to take the pivot's place. */
    vertextags[pivotindex] = vertextags[0];
    *pivotptr = * (struct vertexshort *) vertices;
    for (j = 3; j < 3 + attribcount; j++) {
      /* Swap the pivot's attributes with the first vertex's. */
      tempreal = pivotptr->coord[j];
      pivotptr->coord[j] = ((struct vertexshort *) vertices)->coord[j];
      ((struct vertexshort *) vertices)->coord[j] = tempreal;
    }
  }

  /* Partition the array. */
  leftindex = 0;
  leftptr = (struct vertexshort *) vertices;
  rightindex = vertexcount;
  rightptr = (struct vertexshort *) &vertices[vertexcount * vertexbytes];
  do {
    /* Find a vertex whose z-order position is too large for the left. */
    do {
      leftindex++;
      leftptr = (struct vertexshort *) (((char *) leftptr) + vertexbytes);
    } while ((leftindex < rightindex) &&
             zorderbefore(leftptr->coord[0], leftptr->coord[1],
                          leftptr->coord[2], pivotx, pivoty, pivotz));
    /* Find a vertex whose z-order position is too small for the right. */
    do {
      rightindex--;
      rightptr = (struct vertexshort *) (((char *) rightptr) - vertexbytes);
    } while ((leftindex <= rightindex) &&
             zorderbefore(pivotx, pivoty, pivotz, rightptr->coord[0],
                          rightptr->coord[1], rightptr->coord[2]));

    if (leftindex < rightindex) {
      /* Swap the left and right vertices. */
      temptag = vertextags[rightindex];
      vertextags[rightindex] = vertextags[leftindex];
      vertextags[leftindex] = temptag;
      tempvertex = *rightptr;
      *rightptr = *leftptr;
      *leftptr = tempvertex;
      for (j = 3; j < 3 + attribcount; j++) {
        tempreal = rightptr->coord[j];
        rightptr->coord[j] = leftptr->coord[j];
        leftptr->coord[j] = tempreal;
      }
    }
  } while (leftindex < rightindex);

  /* Place the pivot in the middle of the partition by swapping with the */
  /*   right vertex.                                                     */
  vertextags[0] = vertextags[rightindex];
  vertextags[rightindex] = pivottag;
  * (struct vertexshort *) vertices = *rightptr;
  *rightptr = pivotvertex;
  for (j = 3; j < 3 + attribcount; j++) {
    /* Swap the right vertex's attributes with the pivot's. */
    tempreal = rightptr->coord[j];
    rightptr->coord[j] = ((struct vertexshort *) vertices)->coord[j];
    ((struct vertexshort *) vertices)->coord[j] = tempreal;
  }

  if (rightindex > 1) {
    /* Recursively sort the left subset. */
    inputvertexsort(vertices, vertextags, rightindex, vertexbytes,
                    attribcount);
  }
  if (rightindex < vertexcount - 2) {
    /* Recursively sort the right subset. */
    inputvertexsort(&vertices[(rightindex + 1) * vertexbytes],
                    &vertextags[rightindex + 1], vertexcount - rightindex - 1,
                    vertexbytes, attribcount);
  }
}

void inputverticesintopool(char *vertices,
                           struct inputs *in,
                           struct proxipool *pool)
{
  struct vertex *vertexptr;
  struct vertexshort *vertexshortptr;
  starreal *attributes;
  size_t vertexbytes;
  tag newtag;
  arraypoolulong i;
  unsigned int j;

  vertexshortptr = (struct vertexshort *) vertices;
  vertexbytes = sizeof(struct vertexshort) +
                (size_t) in->attribcount * sizeof(starreal);
  for (i = 0; i < in->vertexcount; i++) {
    newtag = proxipoolnew(pool, 0, (void **) &vertexptr);
    vertexptr->coord[0] = vertexshortptr->coord[0];
    vertexptr->coord[1] = vertexshortptr->coord[1];
    vertexptr->coord[2] = vertexshortptr->coord[2];
    vertexptr->mark = vertexshortptr->mark;
    vertexptr->number = in->vertextags[i];
    in->vertextags[i] = newtag;
    if (in->attribcount > 0) {
      attributes = (starreal *) proxipooltag2object2(pool, newtag);
      for (j = 0; j < in->attribcount; j++) {
        attributes[j] = vertexshortptr->coord[3 + j];
      }
    }

    vertexshortptr = (struct vertexshort *) (((char *) vertexshortptr) +
                                             vertexbytes);
  }
}

void inputverticessortstore(char *vertices,
                            struct inputs *in,
                            struct proxipool *pool)
{
  arraypoolulong i;
  tag *tags;

  tags = (tag *) starmalloc((size_t) (in->vertexcount * sizeof(tag)));
  for (i = 0; i < in->vertexcount; i++) {
    tags[i] = (tag) (in->firstnumber + i);
  }

  inputvertexsort(vertices, tags, in->vertexcount,
                  sizeof(struct vertexshort) +
                  (size_t) in->attribcount * sizeof(starreal),
                  in->attribcount);

  in->vertextags = tags;
  inputverticesintopool(vertices, in, pool);
}

FILE *inputverticesreadsortstore(struct behavior *behave,
                                 struct inputs *in,
                                 struct proxipool *pool)
{
  char *vertices;
  FILE *polyfile;

  vertices = inputvertexfile(behave, in, &polyfile);
  proxipoolinit(pool, sizeof(struct vertex),
                (size_t) (in->attribcount * sizeof(starreal)),
                behave->verbose);
  inputverticessortstore(vertices, in, pool);
  starfree(vertices);

  return polyfile;
}

void inputmaketagmap(struct proxipool *vertexpool,
                     arraypoolulong firstnumber,
                     tag *vertextags)
{
  struct vertex *vertexptr;
  tag iterator;

  iterator = proxipooliterate(vertexpool, NOTATAG);
  while (iterator != NOTATAG) {
    vertexptr = proxipooltag2object(vertexpool, iterator);
    vertextags[vertexptr->number - firstnumber] = iterator;
    iterator = proxipooliterate(vertexpool, iterator);
  }
}

void inputtetrahedra(struct behavior *behave,
                     struct inputs *in,
                     struct proxipool *vertexpool,
                     struct outputs *out,
                     struct tetcomplex *plex)
{
  arraypoolulong corner[4];
  tag cornertag[4];
  char inputline[INPUTLINESIZE];
  char *stringptr;
  FILE *elefile;
  struct vertex *killvertex;
  tag killtag;
  arraypoolulong killnode;
  arraypoolulong elementnumber;
  arraypoolulong boundaryfacecount;
  int elemnodes;
  int result;
  int i;

  /* Read the tetrahedra from an .ele file. */
  if (!behave->quiet) {
    printf("Opening %s.\n", behave->inelefilename);
  }

  elefile = fopen(behave->inelefilename, "r");
  if (elefile == (FILE *) NULL) {
    printf("  Error:  Cannot access file %s.\n", behave->inelefilename);
    starexit(1);
  }

  /* Read number of tetrahedra, number of vertices per tetrahedron, and */
  /*   number of tetrahedron attributes from .ele file.                 */
  stringptr = inputtextline(inputline, elefile, behave->inelefilename);
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
  in->tetcount = (arraypoolulong) strtoull(stringptr, &stringptr, 0);
#else /* no long long type */
  in->tetcount = (arraypoolulong) strtoul(stringptr, &stringptr, 0);
#endif
  stringptr = inputfindfield(stringptr);
  if (*stringptr == '\0') {
    elemnodes = 4;
  } else {
    elemnodes = (int) strtol(stringptr, &stringptr, 0);
    if (elemnodes < 4) {
      printf("Error:  Tetrahedra in %s must have at least 4 vertices.\n",
             behave->inelefilename);
      starexit(1);
    }
  }
  stringptr = inputfindfield(stringptr);
  if (*stringptr == '\0') {
    in->tetattribcount = 0;
  } else {
    in->tetattribcount = (unsigned int) strtoul(stringptr, &stringptr, 0);
  }

  tetcomplexinit(plex, vertexpool, behave->verbose);

  if (!behave->quiet) {
    printf("Reconstructing mesh.\n");
  }

  boundaryfacecount = 0;
  for (elementnumber = behave->firstnumber;
       elementnumber < behave->firstnumber + in->tetcount; elementnumber++) {
    /* Read the tetrahedron's four vertices. */
    stringptr = inputtextline(inputline, elefile, behave->inelefilename);
    for (i = 0; i < 4; i++) {
      stringptr = inputfindfield(stringptr);
      if (*stringptr == '\0') {
        printf("Error:  Tetrahedron %lu is missing vertex %d in %s.\n",
               (unsigned long) elementnumber, i + 1, behave->inelefilename);
        starexit(1);
      } else {
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
        corner[i] = (arraypoolulong) strtoull(stringptr, &stringptr, 0);
#else /* no long long type */
        corner[i] = (arraypoolulong) strtoul(stringptr, &stringptr, 0);
#endif
        if ((corner[i] < behave->firstnumber) ||
            (corner[i] >= behave->firstnumber + in->vertexcount)) {
          printf("Error:  Tetrahedron %lu has an invalid vertex index.\n",
                 (unsigned long) elementnumber);
          starexit(1);
        }
        cornertag[i] = in->vertextags[corner[i] - behave->firstnumber];
      }
    }

    /* Find out about (and throw away) extra nodes. */
    for (i = 4; i < elemnodes; i++) {
      stringptr = inputfindfield(stringptr);
      if (*stringptr != '\0') {
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
        killnode = (arraypoolulong) strtoull(stringptr, &stringptr, 0);
#else /* no long long type */
        killnode = (arraypoolulong) strtoul(stringptr, &stringptr, 0);
#endif
        if ((killnode >= behave->firstnumber) &&
            (killnode < behave->firstnumber + in->vertexcount)) {
          /* Delete the non-corner node if it's not already deleted. */
          killtag = in->vertextags[killnode - behave->firstnumber];
          killvertex = (struct vertex *) proxipooltag2object(vertexpool,
                                                             killtag);
          if (killvertex->number != DEADVERTEX) {
            killvertex->number = DEADVERTEX;
            proxipoolfree(vertexpool, killtag);
            in->deadvertexcount++;
          }
        }
      }
    }

#ifdef SELF_CHECK
    vertexcheckorientation(behave, plex, cornertag[0], cornertag[1],
                           cornertag[2], cornertag[3]);
#endif /* SELF_CHECK */
    result = tetcomplexinserttet(plex, cornertag[0], cornertag[1],
                                 cornertag[2], cornertag[3]);
    if (result > 0) {
      boundaryfacecount += (result - 6);
    }
  }

  fclose(elefile);

  out->vertexcount = in->vertexcount - in->deadvertexcount;
  out->tetcount = tetcomplextetcount(plex);
  out->boundaryfacecount = boundaryfacecount;
  out->facecount = 2 * out->tetcount + (out->boundaryfacecount / 2);
  out->edgecount = out->vertexcount + out->facecount - out->tetcount - 1;
}

/**                                                                         **/
/**                                                                         **/
/********* Input routines end here                                   *********/


/********* Output routines begin here                                *********/
/**                                                                         **/
/**                                                                         **/

/*****************************************************************************/
/*                                                                           */
/*  outputfilefinish()   Write the command line to the output file so the    */
/*                       user can remember how the file was generated.       */
/*                       Close the file.                                     */
/*                                                                           */
/*****************************************************************************/

#ifndef STARLIBRARY

void outputfilefinish(FILE *outfile,
                      int argc,
                      char **argv)
{
  int i;

  fputs("# Generated by", outfile);
  for (i = 0; i < argc; i++) {
    putc(' ', outfile);
    fputs(argv[i], outfile);
  }
  putc('\n', outfile);
  fclose(outfile);
}

#endif /* not PYRLIBRARY */

/*****************************************************************************/
/*                                                                           */
/*  outputpreparevertices()   Determines which vertices are in the mesh, and */
/*                            marks the vertices on the hull boundary.       */
/*                                                                           */
/*  If the -j switch is selected (behave->jettison), the vertices in the     */
/*  mesh are identified and their "number" fields are set to ACTIVEVERTEX.   */
/*                                                                           */
/*  If the -B switch is not selected (behave->nobound), every vertex on the  */
/*  boundary of the convex hull whose mark is zero has its mark set to 1.    */
/*                                                                           */
/*  behave:  Command line switches, operation counts, etc.                   */
/*  vertexpool:  The proxipool of vertices associated with 'plex'.           */
/*  plex:  The tetcomplex in question.                                       */
/*                                                                           */
/*****************************************************************************/

void outputpreparevertices(struct behavior *behave,
                           struct tetcomplex *plex)
{
  struct tetcomplexposition position;
  struct proxipool *pool;
  struct vertex *vertexptr0;
  struct vertex *vertexptr1;
  struct vertex *vertexptr2;
  struct vertex *vertexptr3;
  tag tet[4];

  if (behave->jettison) {
    if (behave->verbose) {
      if (behave->nobound) {
        printf("Identifying vertices in mesh.\n");
      } else {
        printf("Identifying vertices in mesh and marking boundary vertices.\n"
               );
      }
    }
  } else {
    if (behave->nobound) {
      return;
    } else if (behave->verbose) {
      printf("Marking boundary vertices.\n");
    }
  }

  pool = plex->vertexpool;
  /* Iterate through all the tetrahedra in the complex. */
  tetcomplexiteratorinit(plex, &position);
  tetcomplexiterate(&position, tet);
  while (tet[0] != STOP) {
    if ((tet[2] == GHOSTVERTEX) || (tet[3] == GHOSTVERTEX)) {
      if (!behave->nobound) {
        vertexptr0 = (struct vertex *) proxipooltag2object(pool, tet[0]);
        vertexptr1 = (struct vertex *) proxipooltag2object(pool, tet[1]);
        vertexptr2 = (struct vertex *)
          proxipooltag2object(pool, tet[(tet[2] == GHOSTVERTEX) ? 3 : 2]);
        /* These vertices are on the boundary of the triangulation.  If any */
        /*   of them has a vertex mark of zero, change it to one.           */
        if (vertexptr0->mark == 0) {
          vertexptr0->mark = 1;
        }
        if (vertexptr1->mark == 0) {
          vertexptr1->mark = 1;
        }
        if (vertexptr2->mark == 0) {
          vertexptr2->mark = 1;
        }
      }
    } else if (behave->jettison) {
      vertexptr0 = (struct vertex *) proxipooltag2object(pool, tet[0]);
      vertexptr1 = (struct vertex *) proxipooltag2object(pool, tet[1]);
      vertexptr2 = (struct vertex *) proxipooltag2object(pool, tet[2]);
      vertexptr3 = (struct vertex *) proxipooltag2object(pool, tet[3]);
      vertexptr0->number = ACTIVEVERTEX;
      vertexptr1->number = ACTIVEVERTEX;
      vertexptr2->number = ACTIVEVERTEX;
      vertexptr3->number = ACTIVEVERTEX;
    }

    tetcomplexiterate(&position, tet);
  }
}

/*****************************************************************************/
/*                                                                           */
/*  outputvertices()   Write the vertices to a .node file.                   */
/*                                                                           */
/*  in:  Properties of the input geometry.                                   */
/*                                                                           */
/*****************************************************************************/

void outputvertices(struct behavior *behave,
                    struct inputs *in,
                    struct proxipool *pool,
                    arraypoolulong vertexcount,
                    int argc,
                    char **argv)
{
  struct vertex *vertexptr;
  starreal *attributes;
  FILE *outfile;
  tag vertextag;
  arraypoolulong vertexnumber;
  arraypoolulong i;
  unsigned int j;

  if (!behave->quiet) {
    printf("Writing %s.\n", behave->outnodefilename);
  }

  outfile = fopen(behave->outnodefilename, "w");
  if (outfile == (FILE *) NULL) {
    printf("  Error:  Cannot create file %s.\n", behave->outnodefilename);
    starexit(1);
  }

  if (!behave->jettison) {
    vertexcount = proxipoolobjects(pool);
  }

  /* Number of vertices, number of dimensions, number of vertex attributes, */
  /*   and number of boundary markers (zero or one).                        */
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
  if (sizeof(arraypoolulong) > sizeof(long)) {
    fprintf(outfile, "%llu  3  %u  %d\n", (unsigned long long) vertexcount,
            in->attribcount, 1 - behave->nobound);
  } else {
    fprintf(outfile, "%lu  3  %u  %d\n", (unsigned long) vertexcount,
            in->attribcount, 1 - behave->nobound);
  }
#else
  fprintf(outfile, "%lu  3  %u  %d\n", (unsigned long) vertexcount,
          in->attribcount, 1 - behave->nobound);
#endif

  vertexnumber = (arraypoolulong) behave->firstnumber;
  vertextag = proxipooliterate(pool, NOTATAG);
  i = 0;
  while ((behave->jettison && (vertextag != NOTATAG)) ||
         (!behave->jettison && (i < in->vertexcount))) {
    if (!behave->jettison) {
      vertextag = in->vertextags[i];
    }
    vertexptr = (struct vertex *) proxipooltag2object(pool, vertextag);

    if ((vertexptr->number != DEADVERTEX) &&
        (!behave->jettison || (vertexptr->number == ACTIVEVERTEX))) {
      /* Node number, x, y, and z coordinates. */
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
      if (sizeof(arraypoolulong) > sizeof(long)) {
        fprintf(outfile, "%4llu    %.17g  %.17g  %.17g",
                (unsigned long long) vertexnumber,
                (double) vertexptr->coord[0], (double) vertexptr->coord[1],
                (double) vertexptr->coord[2]);
      } else {
        fprintf(outfile, "%4lu    %.17g  %.17g  %.17g",
                (unsigned long) vertexnumber,
                (double) vertexptr->coord[0], (double) vertexptr->coord[1],
                (double) vertexptr->coord[2]);
      }
#else
      fprintf(outfile, "%4lu    %.17g  %.17g  %.17g",
              (unsigned long) vertexnumber,
              (double) vertexptr->coord[0], (double) vertexptr->coord[1],
              (double) vertexptr->coord[2]);
#endif
      if (in->attribcount > 0) {
        attributes = (starreal *) proxipooltag2object2(pool,
                                                       in->vertextags[i]);
        for (j = 0; j < in->attribcount; j++) {
          /* Write an attribute. */
          fprintf(outfile, "  %.17g", (double) attributes[j]);
        }
      }
      if (behave->nobound) {
        putc('\n', outfile);
      } else {
        /* Write the boundary marker. */
        fprintf(outfile, "    %ld\n", (long) vertexptr->mark);
      }

      vertexptr->number = vertexnumber;
      vertexnumber++;
    }

    if (behave->jettison) {
      vertextag = proxipooliterate(pool, vertextag);
    } else {
      i++;
    }
  }

  outputfilefinish(outfile, argc, argv);
}

void outputnumbervertices(struct behavior *behave,
                          struct inputs *in,
                          struct proxipool *pool)
{
  struct vertex *vertexptr;
  tag vertextag;
  arraypoolulong vertexnumber;
  arraypoolulong i;

  vertexnumber = (arraypoolulong) behave->firstnumber;
  if (behave->jettison) {
    vertextag = proxipooliterate(pool, NOTATAG);
    while (vertextag != NOTATAG) {
      vertexptr = (struct vertex *) proxipooltag2object(pool, vertextag);
      if (vertexptr->number == ACTIVEVERTEX) {
        vertexptr->number = vertexnumber;
        vertexnumber++;
      }
      vertextag = proxipooliterate(pool, vertextag);
    }
  } else {
    for (i = 0; i < in->vertexcount; i++) {
      vertexptr = (struct vertex *) proxipooltag2object(pool,
                                                        in->vertextags[i]);
      if (vertexptr->number != DEADVERTEX) {
        vertexptr->number = vertexnumber;
        vertexnumber++;
      }
    }
  }
}

/*****************************************************************************/
/*                                                                           */
/*  outputtetrahedra()   Write the tetrahedra to an .ele file.               */
/*                                                                           */
/*****************************************************************************/

void outputtetrahedra(struct behavior *behave,
                      struct inputs *in,
                      struct tetcomplex *plex,
                      int argc,
                      char **argv)
{
  struct tetcomplexposition position;
  struct proxipool *pool;
  struct vertex *vertexptr0;
  struct vertex *vertexptr1;
  struct vertex *vertexptr2;
  struct vertex *vertexptr3;
  tag tet[4];
  FILE *outfile;
  arraypoolulong tetnumber;

  if (!behave->quiet) {
    printf("Writing %s.\n", behave->outelefilename);
  }

  outfile = fopen(behave->outelefilename, "w");
  if (outfile == (FILE *) NULL) {
    printf("  Error:  Cannot create file %s.\n", behave->outelefilename);
    starexit(1);
  }

  /* Number of tetrahedra, vertices per tetrahedron, attributes */
  /*   per tetrahedron.                                         */
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
  if (sizeof(arraypoolulong) > sizeof(long)) {
    fprintf(outfile, "%llu  %d  0\n",
            (unsigned long long) tetcomplextetcount(plex),
            (behave->order + 1) * (behave->order + 2) * (behave->order + 3) /
            6);
  } else {
    fprintf(outfile, "%lu  %d  0\n",
            (unsigned long) tetcomplextetcount(plex),
            (behave->order + 1) * (behave->order + 2) * (behave->order + 3) /
            6);
  }
#else
  fprintf(outfile, "%lu  %d  0\n", (unsigned long) tetcomplextetcount(plex),
          (behave->order + 1) * (behave->order + 2) * (behave->order + 3) / 6);
#endif

  pool = plex->vertexpool;
  tetnumber = (arraypoolulong) behave->firstnumber;

  /* Iterate through all the (non-ghost) tetrahedra in the complex. */
  tetcomplexiteratorinit(plex, &position);
  tetcomplexiteratenoghosts(&position, tet);
  while (tet[0] != STOP) {
    vertexptr0 = (struct vertex *) proxipooltag2object(pool, tet[0]);
    vertexptr1 = (struct vertex *) proxipooltag2object(pool, tet[1]);
    vertexptr2 = (struct vertex *) proxipooltag2object(pool, tet[2]);
    vertexptr3 = (struct vertex *) proxipooltag2object(pool, tet[3]);

    /* Tetrahedron number and indices for four vertices. */
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
    if (sizeof(arraypoolulong) > sizeof(long)) {
      fprintf(outfile, "%4llu    %4llu  %4llu  %4llu  %4llu\n",
              (unsigned long long) tetnumber,
              (unsigned long long) vertexptr0->number,
              (unsigned long long) vertexptr1->number,
              (unsigned long long) vertexptr2->number,
              (unsigned long long) vertexptr3->number);
    } else {
      fprintf(outfile, "%4lu    %4lu  %4lu  %4lu  %4lu\n",
              (unsigned long) tetnumber,
              (unsigned long) vertexptr0->number,
              (unsigned long) vertexptr1->number,
              (unsigned long) vertexptr2->number,
              (unsigned long) vertexptr3->number);
    }
#else
    fprintf(outfile, "%4lu    %4lu  %4lu  %4lu  %4lu\n",
            (unsigned long) tetnumber,
            (unsigned long) vertexptr0->number,
            (unsigned long) vertexptr1->number,
            (unsigned long) vertexptr2->number,
            (unsigned long) vertexptr3->number);
#endif

    tetcomplexiteratenoghosts(&position, tet);
    tetnumber++;
  }

  outputfilefinish(outfile, argc, argv);
}

/*****************************************************************************/
/*                                                                           */
/*  outputedges()   Write the edges to an .edge file.                        */
/*                                                                           */
/*****************************************************************************/

void outputedges(struct behavior *behave,
                 struct inputs *in,
                 struct tetcomplex *plex,
                 arraypoolulong edgecount,
                 int argc,
                 char **argv)
{
  struct tetcomplexposition position;
  struct proxipool *pool;
  struct vertex *originptr;
  struct vertex *destinptr;
  tag tet[4];
  tag adjacencies[2];
  FILE *outfile;
  tag origin;
  tag destin;
  tag apex;
  tag stopvtx;
  tag searchvtx;
  tag swaptag;
  arraypoolulong edgenumber;
  int writeflag;
  int i;

  if (!behave->quiet) {
    printf("Writing %s.\n", behave->edgefilename);
  }

  outfile = fopen(behave->edgefilename, "w");
  if (outfile == (FILE *) NULL) {
    printf("  Error:  Cannot create file %s.\n", behave->edgefilename);
    starexit(1);
  }

  /* Number of edges, number of boundary markers (zero or one). */
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
  if (sizeof(arraypoolulong) > sizeof(long)) {
    fprintf(outfile, "%llu  %d\n", (unsigned long long) edgecount,
            1 - behave->nobound);
  } else {
    fprintf(outfile, "%lu  %d\n", (unsigned long) edgecount,
            1 - behave->nobound);
  }
#else
  fprintf(outfile, "%lu  %d\n", (unsigned long) edgecount,
          1 - behave->nobound);
#endif

  pool = plex->vertexpool;
  edgenumber = (arraypoolulong) behave->firstnumber;

  /* Iterate through all the (non-ghost) tetrahedra in the complex. */
  tetcomplexiteratorinit(plex, &position);
  tetcomplexiteratenoghosts(&position, tet);
  while (tet[0] != STOP) {
    /* Look at all six edges of the tetrahedron. */
    for (i = 0; i < 6; i++) {
      if (tet[0] < tet[1]) {
        origin = tet[0];
        destin = tet[1];
        apex = tet[2];
        stopvtx = tet[3];
      } else {
        origin = tet[1];
        destin = tet[0];
        apex = tet[3];
        stopvtx = tet[2];
      }

      searchvtx = apex;
      writeflag = 1;
      do {
        if (!tetcomplexadjacencies(plex, origin, destin, searchvtx,
                                   adjacencies)) {
          printf("Internal error in outputedges():\n");
          printf("  Complex returned tetrahedron that can't be queried.\n");
          internalerror();
        }
        if (adjacencies[0] == GHOSTVERTEX) {
          writeflag = searchvtx == apex;
        }
        searchvtx = adjacencies[0];
        if (searchvtx < apex) {
          writeflag = 0;
        }
      } while (writeflag &&
               (searchvtx != stopvtx) && (searchvtx != GHOSTVERTEX));

      if (writeflag) {
        originptr = (struct vertex *) proxipooltag2object(pool, origin);
        destinptr = (struct vertex *) proxipooltag2object(pool, destin);

        /* Edge number and indices for two vertices. */
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
        if (sizeof(arraypoolulong) > sizeof(long)) {
          fprintf(outfile, "%4llu    %4llu  %4llu",
                  (unsigned long long) edgenumber,
                  (unsigned long long) originptr->number,
                  (unsigned long long) destinptr->number);
        } else {
          fprintf(outfile, "%4lu    %4lu  %4lu",
                  (unsigned long) edgenumber,
                  (unsigned long) originptr->number,
                  (unsigned long) destinptr->number);
        }
#else
        fprintf(outfile, "%4lu    %4lu  %4lu",
                (unsigned long) edgenumber,
                (unsigned long) originptr->number,
                (unsigned long) destinptr->number);
#endif
        if (behave->nobound) {
          putc('\n', outfile);
        } else if (searchvtx == GHOSTVERTEX) {
          fputs("  1\n", outfile);
        } else {
          fputs("  0\n", outfile);
        }

        edgenumber++;
      }

      /* The following shift cycles (tet[0], tet[1]) through all the edges   */
      /*   while maintaining the tetrahedron's orientation.  The schedule is */
      /*   i = 0:  0 1 2 3 => 1 2 0 3                                        */
      /*   i = 1:  1 2 0 3 => 1 3 2 0                                        */
      /*   i = 2:  1 3 2 0 => 3 2 1 0                                        */
      /*   i = 3:  3 2 1 0 => 3 0 2 1                                        */
      /*   i = 4:  3 0 2 1 => 0 2 3 1                                        */
      /*   i = 5:  0 2 3 1 => 0 1 2 3 (which isn't used).                    */
      if ((i & 1) == 0) {
        swaptag = tet[0];
        tet[0] = tet[1];
        tet[1] = tet[2];
        tet[2] = swaptag;
      } else {
        swaptag = tet[3];
        tet[3] = tet[2];
        tet[2] = tet[1];
        tet[1] = swaptag;
      }
    }

    tetcomplexiteratenoghosts(&position, tet);
  }

  outputfilefinish(outfile, argc, argv);
}

/*****************************************************************************/
/*                                                                           */
/*  outputfaces()   Write the triangular faces to a .face file.              */
/*                                                                           */
/*****************************************************************************/

void outputfaces(struct behavior *behave,
                 struct inputs *in,
                 struct tetcomplex *plex,
                 arraypoolulong facecount,
                 int argc,
                 char **argv)
{
  struct tetcomplexposition position;
  struct proxipool *pool;
  struct vertex *vertexptr0;
  struct vertex *vertexptr1;
  struct vertex *vertexptr2;
  tag tet[4];
  tag adjacencies[2];
  FILE *outfile;
  arraypoolulong facenumber;
  int i;

  if (!behave->quiet) {
    printf("Writing %s.\n", behave->facefilename);
  }

  outfile = fopen(behave->facefilename, "w");
  if (outfile == (FILE *) NULL) {
    printf("  Error:  Cannot create file %s.\n", behave->facefilename);
    starexit(1);
  }

  /* Number of triangular faces, number of boundary markers (zero or one). */
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
  if (sizeof(arraypoolulong) > sizeof(long)) {
    fprintf(outfile, "%llu  %d\n", (unsigned long long) facecount,
            1 - behave->nobound);
  } else {
    fprintf(outfile, "%lu  %d\n", (unsigned long) facecount,
            1 - behave->nobound);
  }
#else
  fprintf(outfile, "%lu  %d\n", (unsigned long) facecount,
          1 - behave->nobound);
#endif

  pool = plex->vertexpool;
  facenumber = (arraypoolulong) behave->firstnumber;

  /* Iterate through all the (non-ghost) tetrahedra in the complex. */
  tetcomplexiteratorinit(plex, &position);
  tetcomplexiteratenoghosts(&position, tet);
  while (tet[0] != STOP) {
    /* Look at all four faces of the tetrahedron. */
    for (i = 0; i < 4; i++) {
      if (!tetcomplexadjacencies(plex, tet[i ^ 1], tet[i ^ 2], tet[i ^ 3],
                                 adjacencies)) {
        printf("Internal error in outputfaces():\n");
        printf("  Iterator returned tetrahedron that can't be queried.\n");
        internalerror();
      }

      /* `adjacencies[1]' is the apex of the tetrahedron adjoining this   */
      /*   tetrahedron on the face (tet[i ^ 1], tet[i ^ 2], tet[i ^ 3]).  */
      /*   So that each face is written only once, write the face if this */
      /*   tetrahedron's apex tag is smaller than the neighbor's.  (Note  */
      /*   that the ghost tetrahedron has the largest tag of all.)        */
      if (tet[i] < adjacencies[1]) {
        /* The vertices of the face are written in counterclockwise order */
        /*   as viewed from _outside_ this tetrahedron.                   */
        vertexptr0 = (struct vertex *) proxipooltag2object(pool, tet[i ^ 3]);
        vertexptr1 = (struct vertex *) proxipooltag2object(pool, tet[i ^ 2]);
        vertexptr2 = (struct vertex *) proxipooltag2object(pool, tet[i ^ 1]);

        /* Face number and indices for three vertices. */
#if (defined(LLONG_MAX) || defined(LONG_LONG_MAX) || defined(LONGLONG_MAX))
        if (sizeof(arraypoolulong) > sizeof(long)) {
          fprintf(outfile, "%4llu    %4llu  %4llu  %4llu",
                  (unsigned long long) facenumber,
                  (unsigned long long) vertexptr0->number,
                  (unsigned long long) vertexptr1->number,
                  (unsigned long long) vertexptr2->number);
        } else {
          fprintf(outfile, "%4lu    %4lu  %4lu  %4lu",
                  (unsigned long) facenumber,
                  (unsigned long) vertexptr0->number,
                  (unsigned long) vertexptr1->number,
                  (unsigned long) vertexptr2->number);
        }
#else
        fprintf(outfile, "%4lu    %4lu  %4lu  %4lu",
                (unsigned long) facenumber,
                (unsigned long) vertexptr0->number,
                (unsigned long) vertexptr1->number,
                (unsigned long) vertexptr2->number);
#endif
        if (behave->nobound) {
          putc('\n', outfile);
        } else if (adjacencies[1] == GHOSTVERTEX) {
          fputs("  1\n", outfile);
        } else {
          fputs("  0\n", outfile);
        }

        facenumber++;
      }
    }

    tetcomplexiteratenoghosts(&position, tet);
  }

  outputfilefinish(outfile, argc, argv);
}

/**                                                                         **/
/**                                                                         **/
/********* Output routines end here                                  *********/


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataFlowExtensionsFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkPolyDataFlowExtensionsFilter.h,v $
Language:  C++
Date:      $Date: 2006/07/07 10:46:19 $
Version:   $Revision: 1.6 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkPolyDataFlowExtensionsFilter - remove the end caps of a surface at flow inlets/outlets and append a cylinder with matching radius that follows the centerline path.  
// .SECTION Description
//  Various options are explained below:
//  - ExtensionMode: method for computing the normal for extension, can be "centerlinedirection" or "boundarynormal"
//  - InterpolationMode: method for computing interpolation from the model section to a circular section, can be "linear" or "thinplatespline"

#ifndef __vtkvmtkPolyDataFlowExtensionsFilter_h
#define __vtkvmtkPolyDataFlowExtensionsFilter_h

#include "vtkPolyDataAlgorithm.h"
#include "vtkPolyData.h"
#include "vtkIdList.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataFlowExtensionsFilter : public vtkPolyDataAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkPolyDataFlowExtensionsFilter,vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkPolyDataFlowExtensionsFilter *New();
  
  vtkSetObjectMacro(Centerlines,vtkPolyData);
  vtkGetObjectMacro(Centerlines,vtkPolyData);

  vtkSetMacro(ExtensionRatio,double);
  vtkGetMacro(ExtensionRatio,double);

  vtkSetMacro(ExtensionLength,double);
  vtkGetMacro(ExtensionLength,double);

  vtkSetMacro(ExtensionRadius,double);
  vtkGetMacro(ExtensionRadius,double);

  vtkSetMacro(TransitionRatio,double);
  vtkGetMacro(TransitionRatio,double);

  vtkSetMacro(Sigma,double);
  vtkGetMacro(Sigma,double);

  vtkSetMacro(CenterlineNormalEstimationDistanceRatio,double);
  vtkGetMacro(CenterlineNormalEstimationDistanceRatio,double);

  vtkSetMacro(AdaptiveExtensionLength,int);
  vtkGetMacro(AdaptiveExtensionLength,int);
  vtkBooleanMacro(AdaptiveExtensionLength,int);

  vtkSetMacro(AdaptiveExtensionRadius,int);
  vtkGetMacro(AdaptiveExtensionRadius,int);
  vtkBooleanMacro(AdaptiveExtensionRadius,int);

  vtkSetMacro(NumberOfBoundaryPoints,int);
  vtkGetMacro(NumberOfBoundaryPoints,int);

  vtkSetMacro(AdaptiveNumberOfBoundaryPoints,int);
  vtkGetMacro(AdaptiveNumberOfBoundaryPoints,int);
  vtkBooleanMacro(AdaptiveNumberOfBoundaryPoints,int);

  vtkSetObjectMacro(BoundaryIds,vtkIdList);
  vtkGetObjectMacro(BoundaryIds,vtkIdList);

  vtkSetMacro(ExtensionMode,int);
  vtkGetMacro(ExtensionMode,int);
  void SetExtensionModeToUseNormalToBoundary()
  { this->SetExtensionMode(USE_NORMAL_TO_BOUNDARY); }
  void SetExtensionModeToUseCenterlineDirection()
  { this->SetExtensionMode(USE_CENTERLINE_DIRECTION); }

  vtkSetMacro(InterpolationMode,int);
  vtkGetMacro(InterpolationMode,int);
  void SetInterpolationModeToLinear()
  { this->SetInterpolationMode(USE_LINEAR_INTERPOLATION); }
  void SetInterpolationModeToThinPlateSpline()
  { this->SetInterpolationMode(USE_THIN_PLATE_SPLINE_INTERPOLATION); }

//BTX
  enum {
    USE_NORMAL_TO_BOUNDARY = 0,
    USE_CENTERLINE_DIRECTION
  };

  enum {
    USE_LINEAR_INTERPOLATION = 0,
    USE_THIN_PLATE_SPLINE_INTERPOLATION
  };
//ETX

  protected:
  vtkvmtkPolyDataFlowExtensionsFilter();
  ~vtkvmtkPolyDataFlowExtensionsFilter();

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  vtkPolyData* Centerlines;

  double ExtensionRatio;
  double ExtensionLength;
  double ExtensionRadius;

  double TransitionRatio;
  double Sigma;

  double CenterlineNormalEstimationDistanceRatio;

  int AdaptiveExtensionLength;
  int AdaptiveExtensionRadius;

  int NumberOfBoundaryPoints;
  int AdaptiveNumberOfBoundaryPoints;

  int ExtensionMode;
  int InterpolationMode;

  vtkIdList* BoundaryIds;

  private:
  vtkvmtkPolyDataFlowExtensionsFilter(const vtkvmtkPolyDataFlowExtensionsFilter&);  // Not implemented.
  void operator=(const vtkvmtkPolyDataFlowExtensionsFilter&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Misc/vtkvmtkBoundaryLayerGenerator.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkBoundaryLayerGenerator.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:47:48 $
Version:   $Revision: 1.7 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkBoundaryLayerGenerator.h"
#include "vtkvmtkConstants.h"
#include "vtkUnstructuredGrid.h"
#include "vtkPointData.h"
#include "vtkCellData.h"
#include "vtkPoints.h"
#include "vtkCellArray.h"
#include "vtkDoubleArray.h"
#include "vtkIntArray.h"
#include "vtkUnsignedCharArray.h"
#include "vtkMath.h"
#include "vtkLine.h"
#include "vtkTriangle.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkBoundaryLayerGenerator);

vtkvmtkBoundaryLayerGenerator::vtkvmtkBoundaryLayerGenerator()
{
  this->WarpVectorsArrayName = NULL;
  this->LayerThicknessArrayName = NULL;

  this->WarpVectorsArray = NULL;
  this->LayerThicknessArray = NULL;

  this->UseWarpVectorMagnitudeAsThickness = 0;
  this->ConstantThickness = 0;

  this->LayerThickness = 1.0;
  this->LayerThicknessRatio = 1.0; // ratio with respect to the LayerThickness (both constant and local)
  this->MaximumLayerThickness = VTK_VMTK_LARGE_DOUBLE;
  this->NumberOfSubLayers = 1;
  this->SubLayerRatio = 1.0; // thickness ratio between successive sublayers (moving from the surface)
  this->NumberOfSubsteps = 2000;
  this->Relaxation = 0.01;
  this->LocalCorrectionFactor = 0.45;

  this->IncludeSurfaceCells = 0;
  this->IncludeSidewallCells = 0;
  this->NegateWarpVectors = 0;

  this->CellEntityIdsArrayName = NULL;
  this->InnerSurfaceCellEntityId = 0;
  this->OuterSurfaceCellEntityId = 0;
  this->SidewallCellEntityId = 0;
  this->VolumeCellEntityId = 0;

  this->InnerSurface = NULL;
}

vtkvmtkBoundaryLayerGenerator::~vtkvmtkBoundaryLayerGenerator()
{
  if (this->WarpVectorsArrayName)
    {
    delete[] this->WarpVectorsArrayName;
    this->WarpVectorsArrayName = NULL;
    }

  if (this->LayerThicknessArrayName)
    {
    delete[] this->LayerThicknessArrayName;
    this->LayerThicknessArrayName = NULL;
    }

  if (this->InnerSurface)
    {
    this->InnerSurface->Delete();
    this->InnerSurface = NULL;
    }

  if (this->CellEntityIdsArrayName)
    {
    delete[] this->CellEntityIdsArrayName;
    this->CellEntityIdsArrayName = NULL;
    }
}

int vtkvmtkBoundaryLayerGenerator::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkUnstructuredGrid *input = vtkUnstructuredGrid::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkPoints* inputPoints = input->GetPoints();

  if (!this->WarpVectorsArrayName)
    {
    vtkErrorMacro("WarpVectors array name not specified.");
    return 1;
    }

  if (!this->CellEntityIdsArrayName)
    {
    vtkErrorMacro("CellEntityIds array name not specified.");
    return 1;
    }

  if (!input->GetPointData()->GetArray(this->WarpVectorsArrayName))
    {
    vtkErrorMacro(<< "WarpVectors array with name specified does not exist!");
    return 1;
    }

  this->WarpVectorsArray = input->GetPointData()->GetArray(this->WarpVectorsArrayName);
  
  if ((!this->UseWarpVectorMagnitudeAsThickness) && (!this->ConstantThickness))
    {
    if (!this->LayerThicknessArrayName)
      {
      vtkErrorMacro("LayerThickness array name not specified.");
      return 1;
      }

    if (!input->GetPointData()->GetArray(this->LayerThicknessArrayName))
      {
      vtkErrorMacro(<< "LayerThickness array with name specified does not exist!");
      return 1;
      }

    this->LayerThicknessArray = input->GetPointData()->GetArray(this->LayerThicknessArrayName);
    }

  vtkIdType i;

  vtkPoints* outputPoints = vtkPoints::New();
  vtkPoints* warpedPoints = vtkPoints::New();

  vtkCellArray* boundaryLayerCellArray = vtkCellArray::New();
  vtkIdList* boundaryLayerCellTypes = vtkIdList::New();

  vtkIntArray* cellEntityIdsArray = vtkIntArray::New();
  cellEntityIdsArray->SetName(this->CellEntityIdsArrayName);

  vtkIntArray* innerSurfaceCellEntityIdsArray = vtkIntArray::New();
  innerSurfaceCellEntityIdsArray->SetName(this->CellEntityIdsArrayName);
  
  vtkUnsignedCharArray* checkArray = vtkUnsignedCharArray::New();
  checkArray->SetNumberOfTuples(input->GetNumberOfCells());
  checkArray->FillComponent(0,1);

  vtkIdType numberOfInputPoints = inputPoints->GetNumberOfPoints();
  vtkIdType numberOfInputCells = input->GetNumberOfCells();

  int cellType;
  cellType = input->GetCellType(0);  // TODO: check if all elements are consistent
  bool warpQuadratic = false;
  if (cellType == VTK_QUADRATIC_TRIANGLE)
    {
    warpQuadratic = true;
    }

  vtkIdType numberOfLayerPoints = numberOfInputPoints;
  if (warpQuadratic)
    {
    numberOfLayerPoints = 2 * numberOfInputPoints;
    }  

  vtkIdType numberOfOutputPoints = numberOfInputPoints + numberOfLayerPoints * this->NumberOfSubLayers;
  outputPoints->SetNumberOfPoints(numberOfOutputPoints);

  double point[3];
  for (i=0; i<numberOfInputPoints; i++)
    {
    inputPoints->GetPoint(i,point);
    outputPoints->SetPoint(i,point);
    }

  vtkIdType npts, *pts;
  vtkIdType *surfacePts;

  if (this->IncludeSurfaceCells)
    {
    for (i=0; i<numberOfInputCells; i++)
      {
      input->GetCellPoints(i,npts,pts);
      cellType = input->GetCellType(i);
      surfacePts = new vtkIdType[npts];
      switch(cellType)
        {
        case VTK_TRIANGLE:
          boundaryLayerCellTypes->InsertNextId(VTK_TRIANGLE);
          surfacePts[0] = pts[0];
          surfacePts[1] = pts[1];
          surfacePts[2] = pts[2];
          break;
        case VTK_QUAD:
          boundaryLayerCellTypes->InsertNextId(VTK_QUAD);
          surfacePts[0] = pts[0];
          surfacePts[1] = pts[1];
          surfacePts[2] = pts[2];
          surfacePts[3] = pts[3];
          break;
        case VTK_QUADRATIC_TRIANGLE:
          boundaryLayerCellTypes->InsertNextId(VTK_QUADRATIC_TRIANGLE);
          surfacePts[0] = pts[0];
          surfacePts[1] = pts[1];
          surfacePts[2] = pts[2];
          surfacePts[3] = pts[3];
          surfacePts[4] = pts[4];
          surfacePts[5] = pts[5];
          break;
        default:
          vtkErrorMacro(<<"Unsupported surface element.");
          return 1;
          break;
        }
      boundaryLayerCellArray->InsertNextCell(npts,surfacePts);
      cellEntityIdsArray->InsertNextValue(this->InnerSurfaceCellEntityId);
      delete[] surfacePts;
      }
    }

  vtkIdList* edgePointIds = vtkIdList::New();
  vtkIdList* edgeNeighborCellIds = vtkIdList::New();

  double relaxation = this->Relaxation;
  int initialNumberOfSubsteps = this->NumberOfSubsteps / 100;
  int intermediateNumberOfSubsteps = this->NumberOfSubsteps / 10;
  int finalNumberOfSubsteps = this->NumberOfSubsteps - initialNumberOfSubsteps - intermediateNumberOfSubsteps;

  this->BuildWarpVectors(input);
  this->IncrementalWarpVectors(input,initialNumberOfSubsteps,relaxation);
  
  int iteration = 0;
  int check = this->CheckTangle(input,checkArray);  
  if (check==1)
    {
    std::cout <<"untangle procedure.. "<<std::endl; 
    }

  int maximumNumberOfIterations = this->NumberOfSubsteps / 10; 
  while (check==1 && iteration < maximumNumberOfIterations)
    {
    this->LocalUntangle(input,checkArray,this->LocalCorrectionFactor);
    this->IncrementalWarpVectors(input,intermediateNumberOfSubsteps,relaxation);   
    //std::cout << "iteration " << iteration << std::endl;
    check = this->CheckTangle(input,checkArray);
    iteration += 1;
    if (check==0)
      {
      std::cout <<"try last : " ;
      this->IncrementalWarpVectors(input,finalNumberOfSubsteps,relaxation); //questo se alto tira un po la piega che altrimenti si forma
      check = this->CheckTangle(input,checkArray); 
      }
    }  
  
  int k;
  for (k=0; k<this->NumberOfSubLayers; k++)
    {
    warpedPoints->Initialize();
    this->WarpPoints(inputPoints,warpedPoints,k,warpQuadratic);

    for (i=0; i<numberOfLayerPoints; i++)
      {
      warpedPoints->GetPoint(i,point);
      outputPoints->SetPoint(i + numberOfInputPoints + k*numberOfLayerPoints,point);
      }
   
    vtkIdType prismNPts, *prismPts;
    vtkIdType quadNPts, *quadPts;
    for (i=0; i<numberOfInputCells; i++)
      {
      input->GetCellPoints(i,npts,pts);
      cellType = input->GetCellType(i);
      if (cellType == VTK_TRIANGLE || cellType == VTK_QUAD)
        {
        prismNPts = npts * 2;
        prismPts = new vtkIdType[prismNPts];
        quadNPts = 4;
        quadPts = new vtkIdType[quadNPts];
        int j;
        for (j=0; j<npts; j++)
          {
          prismPts[j] = pts[j] + k*numberOfLayerPoints;
          }
        for (j=0; j<npts; j++)
          {
          prismPts[j+npts] = pts[j] + (k+1)*numberOfLayerPoints;
          }
        boundaryLayerCellArray->InsertNextCell(prismNPts,prismPts);
        cellEntityIdsArray->InsertNextValue(this->VolumeCellEntityId);

        if (cellType == VTK_TRIANGLE)
          {
          boundaryLayerCellTypes->InsertNextId(VTK_WEDGE);
          }
        else if (cellType == VTK_QUAD)
          {
          boundaryLayerCellTypes->InsertNextId(VTK_HEXAHEDRON);
          }

        if (this->IncludeSidewallCells)
          {
          for (j=0; j<npts; j++)
            {
            vtkIdType jnext = (j+1) % npts;
            edgePointIds->Initialize();
            edgePointIds->SetNumberOfIds(2);
            edgePointIds->SetId(0,pts[j]);
            edgePointIds->SetId(1,pts[jnext]);
            input->GetCellNeighbors(i,edgePointIds,edgeNeighborCellIds);

            if (edgeNeighborCellIds->GetNumberOfIds() > 0)
              {
              continue;
              }

            quadPts[0] = prismPts[j];
            quadPts[1] = prismPts[jnext];
            quadPts[2] = prismPts[jnext+npts];
            quadPts[3] = prismPts[j+npts];

            boundaryLayerCellArray->InsertNextCell(quadNPts,quadPts);
            boundaryLayerCellTypes->InsertNextId(VTK_QUAD);
            cellEntityIdsArray->InsertNextValue(this->SidewallCellEntityId);
            }
          }
        
        delete[] prismPts;
        delete[] quadPts;
        }
      else if (cellType == VTK_QUADRATIC_TRIANGLE)
        {
        prismNPts = npts * 3 - 3;
        prismPts = new vtkIdType[prismNPts];
        quadNPts = 8;
        quadPts = new vtkIdType[quadNPts];
 
        boundaryLayerCellTypes->InsertNextId(VTK_QUADRATIC_WEDGE);
        
        prismPts[0] = pts[0] + k*numberOfLayerPoints;
        prismPts[1] = pts[1] + k*numberOfLayerPoints;
        prismPts[2] = pts[2] + k*numberOfLayerPoints;

        prismPts[3] = pts[0] + k*numberOfLayerPoints + numberOfLayerPoints;
        prismPts[4] = pts[1] + k*numberOfLayerPoints + numberOfLayerPoints;
        prismPts[5] = pts[2] + k*numberOfLayerPoints + numberOfLayerPoints;

        prismPts[6] = pts[3] + k*numberOfLayerPoints;
        prismPts[7] = pts[4] + k*numberOfLayerPoints;
        prismPts[8] = pts[5] + k*numberOfLayerPoints;

        prismPts[9] = pts[3] + k*numberOfLayerPoints + numberOfLayerPoints;
        prismPts[10] = pts[4] + k*numberOfLayerPoints + numberOfLayerPoints;
        prismPts[11] = pts[5] + k*numberOfLayerPoints + numberOfLayerPoints;

        prismPts[12] = pts[0] + k*numberOfLayerPoints + numberOfLayerPoints/2;
        prismPts[13] = pts[1] + k*numberOfLayerPoints + numberOfLayerPoints/2;
        prismPts[14] = pts[2] + k*numberOfLayerPoints + numberOfLayerPoints/2;

        boundaryLayerCellArray->InsertNextCell(prismNPts,prismPts);
        cellEntityIdsArray->InsertNextValue(this->VolumeCellEntityId);

        if (this->IncludeSidewallCells)
          {
          for (int j=0; j<npts/2; j++)
            {
            vtkIdType jnext = (j+1) % npts;
            edgePointIds->Initialize();
            edgePointIds->SetNumberOfIds(2);
            edgePointIds->SetId(0,pts[j]);
            edgePointIds->SetId(1,pts[jnext]);
            input->GetCellNeighbors(i,edgePointIds,edgeNeighborCellIds);

            if (edgeNeighborCellIds->GetNumberOfIds() > 0)
              {
              continue;
              }

            quadPts[0] = prismPts[j];
            quadPts[1] = prismPts[jnext];
            quadPts[2] = prismPts[jnext+npts/2];
            quadPts[3] = prismPts[j+npts/2];

            quadPts[4] = prismPts[j+npts];
            quadPts[5] = prismPts[jnext+2*npts];
            quadPts[6] = prismPts[j+npts+npts/2];
            quadPts[7] = prismPts[j+2*npts];

            boundaryLayerCellArray->InsertNextCell(quadNPts,quadPts);
            boundaryLayerCellTypes->InsertNextId(VTK_QUAD);
            cellEntityIdsArray->InsertNextValue(this->SidewallCellEntityId);
            }
          }

        delete[] prismPts;
        delete[] quadPts;
        }
      else
        {
        vtkErrorMacro(<<"Unsupported surface element.");
        return 1;
        }
      }

    if (this->IncludeSurfaceCells)
      {
      if (k==this->NumberOfSubLayers-1)
        {
        for (i=0; i<numberOfInputCells; i++)
          {
          input->GetCellPoints(i,npts,pts);
          cellType = input->GetCellType(i);
          surfacePts = new vtkIdType[npts];
          switch(cellType)
            {
            case VTK_TRIANGLE:
              boundaryLayerCellTypes->InsertNextId(VTK_TRIANGLE);
              surfacePts[0] = pts[0] + k*numberOfLayerPoints + numberOfLayerPoints;
              surfacePts[1] = pts[1] + k*numberOfLayerPoints + numberOfLayerPoints;
              surfacePts[2] = pts[2] + k*numberOfLayerPoints + numberOfLayerPoints;
              break;
            case VTK_QUAD:
              boundaryLayerCellTypes->InsertNextId(VTK_QUAD);
              surfacePts[0] = pts[0] + k*numberOfLayerPoints + numberOfLayerPoints;
              surfacePts[1] = pts[1] + k*numberOfLayerPoints + numberOfLayerPoints;
              surfacePts[2] = pts[2] + k*numberOfLayerPoints + numberOfLayerPoints;
              surfacePts[3] = pts[3] + k*numberOfLayerPoints + numberOfLayerPoints;
              break;
            case VTK_QUADRATIC_TRIANGLE:
              boundaryLayerCellTypes->InsertNextId(VTK_QUADRATIC_TRIANGLE);
              surfacePts[0] = pts[0] + k*numberOfLayerPoints + numberOfLayerPoints;
              surfacePts[1] = pts[1] + k*numberOfLayerPoints + numberOfLayerPoints;
              surfacePts[2] = pts[2] + k*numberOfLayerPoints + numberOfLayerPoints;
              surfacePts[3] = pts[3] + k*numberOfLayerPoints + numberOfLayerPoints;
              surfacePts[4] = pts[4] + k*numberOfLayerPoints + numberOfLayerPoints;
              surfacePts[5] = pts[5] + k*numberOfLayerPoints + numberOfLayerPoints;
              break;
            default:
              vtkErrorMacro(<<"Unsupported surface element.");
              return 1;
              break;
            }
          boundaryLayerCellArray->InsertNextCell(npts,surfacePts);
          cellEntityIdsArray->InsertNextValue(this->OuterSurfaceCellEntityId);
          delete[] surfacePts;
          }
        }
      }
    }

  output->SetPoints(outputPoints);

  int* boundaryLayerCellTypesInt = new int[boundaryLayerCellTypes->GetNumberOfIds()];
  for (i=0; i<boundaryLayerCellTypes->GetNumberOfIds(); i++)
    {
    boundaryLayerCellTypesInt[i] = boundaryLayerCellTypes->GetId(i);
    }

  output->SetCells(boundaryLayerCellTypesInt,boundaryLayerCellArray);

  delete[] boundaryLayerCellTypesInt;
  
  output->GetCellData()->AddArray(cellEntityIdsArray);

  if (this->InnerSurface)
    {
    this->InnerSurface->Delete();
    this->InnerSurface = NULL;
    }

  this->InnerSurface = vtkUnstructuredGrid::New();
  this->InnerSurface->DeepCopy(input);

  vtkPoints* innerSurfacePoints = vtkPoints::New();
  innerSurfacePoints->SetNumberOfPoints(numberOfInputPoints);
  for (i=0; i<numberOfInputPoints; i++)
    {
    output->GetPoint(i + numberOfInputPoints * (this->NumberOfSubLayers),point);
    innerSurfacePoints->SetPoint(i,point);
    }

  this->InnerSurface->GetPoints()->DeepCopy(innerSurfacePoints);
  innerSurfaceCellEntityIdsArray->SetNumberOfTuples(this->InnerSurface->GetNumberOfCells());
  innerSurfaceCellEntityIdsArray->FillComponent(0,this->InnerSurfaceCellEntityId);
  this->InnerSurface->GetCellData()->AddArray(innerSurfaceCellEntityIdsArray);

  edgePointIds->Delete();
  edgeNeighborCellIds->Delete();
  
  outputPoints->Delete();
  warpedPoints->Delete();
  boundaryLayerCellArray->Delete();
  boundaryLayerCellTypes->Delete();
  innerSurfacePoints->Delete();

  cellEntityIdsArray->Delete();
  innerSurfaceCellEntityIdsArray->Delete();
  checkArray->Delete();
 
  return 1;
}

void vtkvmtkBoundaryLayerGenerator::BuildWarpVectors(vtkUnstructuredGrid* input)
{
  double warpVector[3];
  double layerThickness;
  
  vtkIdType numberOfInputPoints = input->GetNumberOfPoints();

  for (vtkIdType i=0; i<numberOfInputPoints; i++)
    {
    this->WarpVectorsArray->GetTuple(i,warpVector);
    if (this->NegateWarpVectors)
      {
      warpVector[0] *= -1.0;
      warpVector[1] *= -1.0;
      warpVector[2] *= -1.0;
      }
    layerThickness = 0.0;
    if (this->ConstantThickness)
      {
      layerThickness = this->LayerThickness;
      }
    else if (this->UseWarpVectorMagnitudeAsThickness)
      {
      layerThickness = vtkMath::Norm(warpVector);
      }
    else
      {
      layerThickness = this->LayerThicknessArray->GetComponent(i,0);
      layerThickness *= this->LayerThicknessRatio;
      }
    if (layerThickness > this->MaximumLayerThickness)
      {
      layerThickness = this->MaximumLayerThickness;
      } 
    vtkMath::Normalize(warpVector);
    warpVector[0] = warpVector[0] * layerThickness;
    warpVector[1] = warpVector[1] * layerThickness;
    warpVector[2] = warpVector[2] * layerThickness;
    
    this->WarpVectorsArray->SetTuple(i,warpVector); 
    } 
}

void vtkvmtkBoundaryLayerGenerator::IncrementalWarpVectors(vtkUnstructuredGrid* input, int numberOfSubsteps, double relaxation)
{   
  vtkPoints* inputPoints = input->GetPoints();
  vtkPoints* warpedPoints = vtkPoints::New();    
  vtkIdType numberOfInputPoints = inputPoints->GetNumberOfPoints();    

  vtkPoints* basePoints = vtkPoints::New();
  basePoints->DeepCopy(inputPoints);

  for (int l=0; l<numberOfSubsteps; l++)
    {
    this->IncrementalWarpPoints(input, basePoints, warpedPoints, l, numberOfSubsteps, relaxation);
    basePoints->DeepCopy(warpedPoints);
    }

  double warpVector[3], basePoint[3], warpedPoint[3];
  for (vtkIdType j=0; j<numberOfInputPoints; j++)
    {
    inputPoints->GetPoint(j,basePoint);
    warpedPoints->GetPoint(j,warpedPoint);
    this->WarpVectorsArray->GetTuple(j,warpVector);
    double layerThickness=vtkMath::Norm(warpVector);
    warpVector[0] = warpedPoint[0] - basePoint[0];
    warpVector[1] = warpedPoint[1] - basePoint[1];
    warpVector[2] = warpedPoint[2] - basePoint[2];
    vtkMath::Normalize(warpVector); 
    warpVector[0] = warpVector[0] * layerThickness; 
    warpVector[1] = warpVector[1] * layerThickness; 
    warpVector[2] = warpVector[2] * layerThickness;  
    this->WarpVectorsArray->SetTuple(j,warpVector);
    }
    
  warpedPoints->Delete();
  basePoints->Delete();
}

int vtkvmtkBoundaryLayerGenerator::CheckTangle(vtkUnstructuredGrid* input, vtkUnsignedCharArray* checkArray)
{
  vtkIdList* pointList=vtkIdList::New();
  
  double warpVector1[3], warpVector2[3],  warpVector3[3];
  double basePoint1[3], basePoint2[3], basePoint3[3];
  double warpedPoint1[3], warpedPoint2[3], warpedPoint3[3];
  double baseNormal[3], warpedNormal[3];
  
  int found = 0;
  int check = 0;
  for (vtkIdType j=0; j<input->GetNumberOfCells(); j++)
    {
    input->GetCellPoints(j,pointList);
    //points on base triangle
    input->GetPoint(pointList->GetId(0),basePoint1);
    input->GetPoint(pointList->GetId(1),basePoint2);
    input->GetPoint(pointList->GetId(2),basePoint3);
    
    this->WarpVectorsArray->GetTuple(pointList->GetId(0),warpVector1);
    this->WarpVectorsArray->GetTuple(pointList->GetId(1),warpVector2);
    this->WarpVectorsArray->GetTuple(pointList->GetId(2),warpVector3);
                                  
    //points on extruded triangle
    warpedPoint1[0] = basePoint1[0] + warpVector1[0];
    warpedPoint1[1] = basePoint1[1] + warpVector1[1];
    warpedPoint1[2] = basePoint1[2] + warpVector1[2];
    warpedPoint2[0] = basePoint2[0] + warpVector2[0];
    warpedPoint2[1] = basePoint2[1] + warpVector2[1];
    warpedPoint2[2] = basePoint2[2] + warpVector2[2];           
    warpedPoint3[0] = basePoint3[0] + warpVector3[0];
    warpedPoint3[1] = basePoint3[1] + warpVector3[1];
    warpedPoint3[2] = basePoint3[2] + warpVector3[2];          
    
    //normals on base triangle (baseNormal) and normals on extruded triangle (warpedNormal)
    vtkTriangle::ComputeNormal(basePoint1,basePoint2,basePoint3,baseNormal);
    vtkTriangle::ComputeNormal(warpedPoint1,warpedPoint2,warpedPoint3,warpedNormal);
    double prod = vtkMath::Dot(baseNormal,warpedNormal);
    double baseArea = vtkTriangle::TriangleArea(basePoint1,basePoint2,basePoint3);
    double warpedArea = vtkTriangle::TriangleArea(warpedPoint1,warpedPoint2,warpedPoint3);
    double testArea = warpedArea / baseArea;    
    if (prod < 0 || testArea <= 0.1 )
      {
      check = 1;
      found = found + 1;
      checkArray->SetValue(j,1); 
      }
    else
      {
      checkArray->SetValue(j,0);  
      }
    }
  //std::cout << found <<" tangle triangles found"<<std::endl;
  
  pointList->Delete();
  return check;
}

void vtkvmtkBoundaryLayerGenerator::LocalUntangle(vtkUnstructuredGrid* input, vtkUnsignedCharArray* checkArray, double alpha)
{
  vtkIdList* pointList=vtkIdList::New();
  vtkIdList* pointList2=vtkIdList::New();
  vtkIdList* cellList=vtkIdList::New();
  
  double warpVector1[3], warpVector2[3], warpVector3[3];
  double w1s[3], w2s[3], w3s[3], n[3]; 
  double point1[3], point2[3], point3[3];
  double c1[3], c2[3],  c3[3];

  vtkDoubleArray* correctionArray = vtkDoubleArray::New();
  correctionArray->SetName("correctionVectors");
  correctionArray->SetNumberOfComponents(3);
  correctionArray->SetNumberOfTuples(input->GetNumberOfPoints());
  correctionArray->FillComponent(0,0.0);
  correctionArray->FillComponent(1,0.0);
  correctionArray->FillComponent(2,0.0);
  input->GetPointData()->AddArray(correctionArray);   
  
  for (vtkIdType j=0; j<input->GetNumberOfCells(); j++)
    {
    if (checkArray->GetValue(j)==1)
      {
      input->GetCellPoints(j,pointList);
      this->WarpVectorsArray->GetTuple(pointList->GetId(0),warpVector1);
      this->WarpVectorsArray->GetTuple(pointList->GetId(1),warpVector2);
      this->WarpVectorsArray->GetTuple(pointList->GetId(2),warpVector3);
      //eventually we can do it iteratively (relaxation >1)
      double relaxation = 1.0;
      for (int r=0; r<relaxation; r++)
        {
        w1s[0] = w1s[1] = w1s[2] = 0.0;
        w2s[0] = w2s[1] = w2s[2] = 0.0;
        w3s[0] = w3s[1] = w3s[2] = 0.0;
        n[0] = n[1] = n[2] = 0.0;
        input->GetPointCells(pointList->GetId(0),cellList);
        for (int i=0; i<cellList->GetNumberOfIds();i++)
          {
          input->GetCellPoints(i,pointList2);
          input->GetPoint(pointList2->GetId(0),point1);
          input->GetPoint(pointList2->GetId(1),point2);
          input->GetPoint(pointList2->GetId(2),point3);
          vtkTriangle::ComputeNormal(point1,point2,point3,n);         
          w1s[0] += warpVector1[0] - vtkMath::Dot(warpVector1,n) * n[0];
          w1s[1] += warpVector1[1] - vtkMath::Dot(warpVector1,n) * n[1];
          w1s[2] += warpVector1[2] - vtkMath::Dot(warpVector1,n) * n[2];
          }
        vtkMath::Normalize(w1s);
        input->GetPointCells(pointList->GetId(1),cellList);
        for (int i=0; i<cellList->GetNumberOfIds();i++)
          {                       
          input->GetCellPoints(i,pointList2);
          input->GetPoint(pointList2->GetId(0),point1);
          input->GetPoint(pointList2->GetId(1),point2);
          input->GetPoint(pointList2->GetId(2),point3);
          vtkTriangle::ComputeNormal(point1,point2,point3,n); 
          w2s[0] += warpVector2[0] - vtkMath::Dot(warpVector2,n) * n[0];
          w2s[1] += warpVector2[1] - vtkMath::Dot(warpVector2,n) * n[1];
          w2s[2] += warpVector2[2] - vtkMath::Dot(warpVector2,n) * n[2];
          }
        vtkMath::Normalize(w2s);
        input->GetPointCells(pointList->GetId(2),cellList);
        for (int i=0; i<cellList->GetNumberOfIds();i++)
          {                       
          input->GetCellPoints(i,pointList2);
          input->GetPoint(pointList2->GetId(0),point1);
          input->GetPoint(pointList2->GetId(1),point2);
          input->GetPoint(pointList2->GetId(2),point3);
          vtkTriangle::ComputeNormal(point1,point2,point3,n);
          w3s[0] += warpVector3[0] - vtkMath::Dot(warpVector3,n) * n[0];
          w3s[1] += warpVector3[1] - vtkMath::Dot(warpVector3,n) * n[1];
          w3s[2] += warpVector3[2] - vtkMath::Dot(warpVector3,n) * n[2]; 
          }
        vtkMath::Normalize(w3s);
        correctionArray->GetTuple(pointList->GetId(0),c1);
        correctionArray->GetTuple(pointList->GetId(1),c2);
        correctionArray->GetTuple(pointList->GetId(2),c3);
        c1[0] = c1[0] + alpha * w2s[0] + alpha * w3s[0];
        c1[1] = c1[1] + alpha * w2s[1] + alpha * w3s[1];
        c1[2] = c1[2] + alpha * w2s[2] + alpha * w3s[2];
        c2[0] = c2[0] + alpha * w1s[0] + alpha * w3s[0];
        c2[1] = c2[1] + alpha * w1s[1] + alpha * w3s[1];
        c2[2] = c2[2] + alpha * w1s[2] + alpha * w3s[2];
        c3[0] = c3[0] + alpha * w2s[0] + alpha * w1s[0];
        c3[1] = c3[1] + alpha * w2s[1] + alpha * w1s[1];
        c3[2] = c3[2] + alpha * w2s[2] + alpha * w1s[2];
        correctionArray->SetTuple3(pointList->GetId(0),c1[0],c1[1],c1[2]);
        correctionArray->SetTuple3(pointList->GetId(1),c2[0],c2[1],c2[2]);
        correctionArray->SetTuple3(pointList->GetId(2),c3[0],c3[1],c3[2]);                
        }
      }         
    }

  double warp[3], correction[3];  
  for (vtkIdType i=0; i<input->GetNumberOfPoints();i++)
    {
    this->WarpVectorsArray->GetTuple(i,warp);
    double layerThickness=vtkMath::Norm(warp);
    correctionArray->GetTuple(i,correction);
    warp[0] = warp[0] + correction[0];
    warp[1] = warp[1] + correction[1];
    warp[2] = warp[2] + correction[2];       
    vtkMath::Normalize(warp);
    warp[0] = warp[0] * layerThickness;
    warp[1] = warp[1] * layerThickness;
    warp[2] = warp[2] * layerThickness;
    this->WarpVectorsArray->SetTuple(i,warp); 
    }
  
  correctionArray->Delete();
  pointList->Delete();
  pointList2->Delete();
  cellList->Delete();  
}

void vtkvmtkBoundaryLayerGenerator::WarpPoints(vtkPoints* inputPoints, vtkPoints* warpedPoints, int subLayerId, bool quadratic)
{
  double point[3], warpedPoint[3], warpVector[3];
  double layerThickness, subLayerThicknessRatio, subLayerThickness;
  double totalLayerZeroSubLayerRatio, subLayerOffsetRatio, subLayerOffset;

  vtkIdType numberOfInputPoints = inputPoints->GetNumberOfPoints();

  totalLayerZeroSubLayerRatio = 0.0;
  int i;
  for (i=0; i<this->NumberOfSubLayers; i++)
    {
    totalLayerZeroSubLayerRatio += pow(this->SubLayerRatio,this->NumberOfSubLayers-i-1);
    }

  subLayerOffsetRatio = 0.0;
  for (i=0; i<subLayerId; i++)
    {
    subLayerOffsetRatio += pow(this->SubLayerRatio,this->NumberOfSubLayers-i-1);
    }
  subLayerOffsetRatio /= totalLayerZeroSubLayerRatio;

  subLayerThicknessRatio = pow(this->SubLayerRatio,this->NumberOfSubLayers-subLayerId-1) / totalLayerZeroSubLayerRatio;

  if (!quadratic)
    {
    warpedPoints->SetNumberOfPoints(numberOfInputPoints);
    }
  else
    {
    warpedPoints->SetNumberOfPoints(2*numberOfInputPoints);
    }

  for (i=0; i<numberOfInputPoints; i++)
    {
    inputPoints->GetPoint(i,point);
    this->WarpVectorsArray->GetTuple(i,warpVector);

    layerThickness = vtkMath::Norm(warpVector);

    vtkMath::Normalize(warpVector);

    subLayerOffset = subLayerOffsetRatio * layerThickness;
    subLayerThickness = subLayerThicknessRatio * layerThickness;

    if (quadratic)
      {
      warpedPoint[0] = point[0] + 0.5 * warpVector[0] * (subLayerOffset + subLayerThickness);
      warpedPoint[1] = point[1] + 0.5 * warpVector[1] * (subLayerOffset + subLayerThickness);
      warpedPoint[2] = point[2] + 0.5 * warpVector[2] * (subLayerOffset + subLayerThickness);
      warpedPoints->SetPoint(i,warpedPoint);
      warpedPoint[0] = point[0] + warpVector[0] * (subLayerOffset + subLayerThickness);
      warpedPoint[1] = point[1] + warpVector[1] * (subLayerOffset + subLayerThickness);
      warpedPoint[2] = point[2] + warpVector[2] * (subLayerOffset + subLayerThickness);
      warpedPoints->SetPoint(i+numberOfInputPoints,warpedPoint);
      }
    else
      {
      warpedPoint[0] = point[0] + warpVector[0] * (subLayerOffset + subLayerThickness);
      warpedPoint[1] = point[1] + warpVector[1] * (subLayerOffset + subLayerThickness);
      warpedPoint[2] = point[2] + warpVector[2] * (subLayerOffset + subLayerThickness);
      warpedPoints->SetPoint(i,warpedPoint);
      }
    }
}

void vtkvmtkBoundaryLayerGenerator::IncrementalWarpPoints(vtkUnstructuredGrid* input, vtkPoints* basePoints, vtkPoints* warpedPoints, int substep, int numberOfSubsteps, double relaxation)
{
  double point[3], warpedPoint[3], warpVector[3];
  double layerThickness;

  vtkIdType numberOfInputPoints = basePoints->GetNumberOfPoints();

  warpedPoints->SetNumberOfPoints(numberOfInputPoints);

  for (vtkIdType i=0; i<numberOfInputPoints; i++)
    {
    basePoints->GetPoint(i,point);
    this->WarpVectorsArray->GetTuple(i,warpVector);
    
    layerThickness = vtkMath::Norm(warpVector); 
    vtkMath::Normalize(warpVector);
    
    layerThickness /= numberOfSubsteps;

    warpedPoint[0] = point[0] + warpVector[0] * layerThickness;
    warpedPoint[1] = point[1] + warpVector[1] * layerThickness;
    warpedPoint[2] = point[2] + warpVector[2] * layerThickness;
    warpedPoints->SetPoint(i,warpedPoint);
    }

  vtkIdType npts, *pts;
  vtkIdList* cellIds = vtkIdList::New();
  vtkIdType cellId;

  vtkIdList* neighborIds = vtkIdList::New();
  vtkIdList* edgePointIds = vtkIdList::New();
  vtkIdList* edgeNeighborCellIds = vtkIdList::New();

  for (vtkIdType j=0; j<numberOfInputPoints; j++)
    {
    input->GetPointCells(j,cellIds);

    neighborIds->Initialize();

    vtkIdType numberOfNeighborCells = cellIds->GetNumberOfIds();
    for (int k=0; k<numberOfNeighborCells; k++)
      {
      cellId = cellIds->GetId(k);
      input->GetCellPoints(cellId,npts,pts);

      neighborIds->InsertUniqueId(pts[0]);
      neighborIds->InsertUniqueId(pts[1]);
      neighborIds->InsertUniqueId(pts[2]);
      }
    neighborIds->DeleteId(j);

    int numberOfNeighbors = neighborIds->GetNumberOfIds();

    bool onEdge = false;
    edgePointIds->Initialize();
    edgeNeighborCellIds->Initialize();
    edgePointIds->InsertId(0,j);
    for (int k=0; k<numberOfNeighbors; k++)
      {
      edgePointIds->InsertId(1,neighborIds->GetId(k));
      input->GetCellNeighbors(-1,edgePointIds,edgeNeighborCellIds);
      if (edgeNeighborCellIds->GetNumberOfIds() < 2)
        {
        onEdge = true;
        break;
        }
      }

    if (onEdge)
      {
      continue;
      }

    double barycenter[3];
    barycenter[0] = barycenter[1] = barycenter[2] = 0.0;
    double neighborPoint[3];
    for (int k=0; k<numberOfNeighbors; k++)
      {
      warpedPoints->GetPoint(neighborIds->GetId(k),neighborPoint);
      barycenter[0] += neighborPoint[0];
      barycenter[1] += neighborPoint[1];
      barycenter[2] += neighborPoint[2];
      }
    barycenter[0] /= numberOfNeighbors;
    barycenter[1] /= numberOfNeighbors;
    barycenter[2] /= numberOfNeighbors;

    warpedPoints->GetPoint(j,warpedPoint);

    // TODO: find out if the current surface is intersecting the original 
    // input surface (not the input surface at this iteration) and in that 
    // case (before it gets too close) stop the warp

    warpedPoint[0] += relaxation * (barycenter[0] - warpedPoint[0]);
    warpedPoint[1] += relaxation * (barycenter[1] - warpedPoint[1]);
    warpedPoint[2] += relaxation * (barycenter[2] - warpedPoint[2]);

    warpedPoints->SetPoint(j,warpedPoint);
    }

  cellIds->Delete();
  neighborIds->Delete();
}

void vtkvmtkBoundaryLayerGenerator::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineMetricFilter.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkPolyDataCenterlineMetricFilter.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:43 $
  Version:   $Revision: 1.8 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkPolyDataCenterlineMetricFilter - Base class for evaluating metrics over a centerline onto a surface. 
// .SECTION Description
// Pure virtual functions.

#ifndef __vtkvmtkPolyDataCenterlineMetricFilter_h
#define __vtkvmtkPolyDataCenterlineMetricFilter_h

#include "vtkPolyDataAlgorithm.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"

#include "vtkPolyData.h"

class vtkDataArray;

class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataCenterlineMetricFilter : public vtkPolyDataAlgorithm
{
public:
  vtkTypeMacro(vtkvmtkPolyDataCenterlineMetricFilter,vtkPolyDataAlgorithm);

  vtkSetStringMacro(MetricArrayName);
  vtkGetStringMacro(MetricArrayName);

  vtkSetStringMacro(GroupIdsArrayName);
  vtkGetStringMacro(GroupIdsArrayName);

  vtkSetObjectMacro(Centerlines,vtkPolyData);
  vtkGetObjectMacro(Centerlines,vtkPolyData);

  vtkSetMacro(UseRadiusInformation,int);
  vtkGetMacro(UseRadiusInformation,int);
  vtkBooleanMacro(UseRadiusInformation,int);

  vtkSetStringMacro(RadiusArrayName);
  vtkGetStringMacro(RadiusArrayName);

  vtkSetStringMacro(CenterlineGroupIdsArrayName);
  vtkGetStringMacro(CenterlineGroupIdsArrayName);

  vtkSetStringMacro(CenterlineIdsArrayName);
  vtkGetStringMacro(CenterlineIdsArrayName);

  vtkSetStringMacro(CenterlineTractIdsArrayName);
  vtkGetStringMacro(CenterlineTractIdsArrayName);

  vtkSetStringMacro(BlankingArrayName);
  vtkGetStringMacro(BlankingArrayName);

  vtkSetMacro(IncludeBifurcations,int);
  vtkGetMacro(IncludeBifurcations,int);
  vtkBooleanMacro(IncludeBifurcations,int);

protected:
  vtkvmtkPolyDataCenterlineMetricFilter();
  ~vtkvmtkPolyDataCenterlineMetricFilter();

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  virtual void EvaluateMetric(vtkIdType pointId, double point[3], vtkIdType groupId, vtkDataArray* metricArray) = 0;

  char* MetricArrayName;
  char* BlankingArrayName;

  char* GroupIdsArrayName;

  vtkPolyData* Centerlines;

  char* RadiusArrayName;
  char* CenterlineGroupIdsArrayName;
  char* CenterlineIdsArrayName;
  char* CenterlineTractIdsArrayName;

  int UseRadiusInformation;
  int IncludeBifurcations;

private:
  vtkvmtkPolyDataCenterlineMetricFilter(const vtkvmtkPolyDataCenterlineMetricFilter&);  // Not implemented.
  void operator=(const vtkvmtkPolyDataCenterlineMetricFilter&);  // Not implemented.
};

#endif



<|start_filename|>distribution/legacy/nsis/postinst.bat<|end_filename|>
@echo off
set VMTK_DIR=%~dp0
set PATH=%VMTK_DIR%bin;%VMTK_DIR%lib\InsightToolkit;%VMTK_DIR%lib\Python;%PATH%
set PYTHONPATH=%VMTK_DIR%lib\site-packages;%VMTK_DIR%lib\vtk-5.6;%VMTK_DIR%lib\vmtk
cd %VMTK_DIR%
cls
echo ################################################################################
echo #################  BYTE COMPILING PYTHON FILES - PLEASE WAIT  ##################
echo ################################################################################
python -mcompileall .
python bin\vmtk-exe.py vmtkimageviewer --help


<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkLinearSystem.cxx<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkLinearSystem.cxx,v $
  Language:  C++
  Date:      $Date: 2006/02/23 09:31:41 $
  Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkLinearSystem.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkLinearSystem);

vtkvmtkLinearSystem::vtkvmtkLinearSystem()
{
  this->A = NULL;
  this->X = NULL;
  this->B = NULL;
}

vtkvmtkLinearSystem::~vtkvmtkLinearSystem()
{
  if (this->A)
    {
    this->A->Delete();
    this->A = NULL;
    }

  if (this->X)
    {
    this->X->Delete();
    this->X = NULL;
    }

  if (this->B)
    {
    this->B->Delete();
    this->B = NULL;
    }
}

int vtkvmtkLinearSystem::CheckSystem()
{
  if (this->A==NULL)
    {
    vtkErrorMacro(<< "System matrix (A) not set!");
    return -1;
    }

  if (this->X==NULL)
    {
    vtkErrorMacro(<< "Unknown vector (x) not provided!");
    return -1;
    }

  if (this->B==NULL)
    {
    vtkErrorMacro(<< "Right-hand side vector (b) not set!");
    return -1;
    }

  if ((this->A->GetNumberOfRows()!=this->X->GetNumberOfElements())||(this->B->GetNumberOfElements()!=this->X->GetNumberOfElements()))
    {
    vtkErrorMacro(<< "System matrix size, unknown vector size and right-hand side vector size do not match!");
    return -1;
    }
  
  return 0;
}



<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkMergeCenterlines.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkMergeCenterlines.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:46:43 $
Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkMergeCenterlines - Combine multiple centerlines which lie within the same branch of a split and grouped centerline.
// .SECTION Description
// If multiple centerlines exist within the same branch, each centerlines point locations are averaged (euclidian interpolation) to result in a branch with only one centerline.

#ifndef __vtkvmtkMergeCenterlines_h
#define __vtkvmtkMergeCenterlines_h

#include "vtkPolyDataAlgorithm.h"
#include "vtkPolyData.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkMergeCenterlines : public vtkPolyDataAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkMergeCenterlines,vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkMergeCenterlines *New();
  
  vtkSetStringMacro(RadiusArrayName);
  vtkGetStringMacro(RadiusArrayName);

  vtkSetStringMacro(GroupIdsArrayName);
  vtkGetStringMacro(GroupIdsArrayName);

  vtkSetStringMacro(CenterlineIdsArrayName);
  vtkGetStringMacro(CenterlineIdsArrayName);

  vtkSetStringMacro(TractIdsArrayName);
  vtkGetStringMacro(TractIdsArrayName);

  vtkSetStringMacro(BlankingArrayName);
  vtkGetStringMacro(BlankingArrayName);

  vtkSetMacro(ResamplingStepLength,double);
  vtkGetMacro(ResamplingStepLength,double);

  vtkSetMacro(MergeBlanked,int);
  vtkGetMacro(MergeBlanked,int);
  vtkBooleanMacro(MergeBlanked,int);

  protected:
  vtkvmtkMergeCenterlines();
  ~vtkvmtkMergeCenterlines();  

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  char* RadiusArrayName;
  char* GroupIdsArrayName;
  char* CenterlineIdsArrayName;
  char* TractIdsArrayName;
  char* BlankingArrayName;

  double ResamplingStepLength;
  int MergeBlanked;

  private:
  vtkvmtkMergeCenterlines(const vtkvmtkMergeCenterlines&);  // Not implemented.
  void operator=(const vtkvmtkMergeCenterlines&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/classify.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*  Routines to classify vertices                                            */
/*                                                                           */
/*****************************************************************************/

/* given a boundary vertex and a list of all of it's
   incident tets, determine if it lies in an input facet */
bool facetvertex(struct tetcomplex *mesh,
                 tag vtx,
                 tag incidenttets[][4],
                 int numincident,
                 starreal normal[3])
{
     bool foundface=false;    /* have we encountered an incident boundary face yet? */
     tag boundfacelist[4][3]; /* list of boundary faces for a particular tet */
     int numboundfaces;       /* number of boundary faces  for a tet */
     starreal refnorm[3] = {0.0, 0.0, 0.0};     /* "reference" normal of first face */
     starreal curnorm[3];     /* the current face's normal */
     starreal e1[3], e2[3];   /* edges for forming cross products */
     starreal *vc1, *vc2, *vc3; /* coordinates of the face vertices */
     starreal dotprod=0.0;        /* dot product of current and reference normal */
     int numfaces=0;            /* total coplanar faces surrounding vertex */
     int i,j;
     
     /* first, check to see if we lie in a facet. to do this, we need
        to build a list of all the boundary faces incident to this vertex.
        this is the same as getting all of the boundary faces of all incident
        tets that include this vertex. */
     
     if (improvebehave.verbosity > 5)
     {
         printf("**** Starting search  for incident boundary faces of vertex %d ****\n", (int) vtx);
         printf("here is what the area around the vertex looks like:\n");
         printtets(mesh, incidenttets, numincident);
     }
     
     /* for each incident tet */
     for (i=0; i<numincident; i++)
     {
         /* collect all the boundary faces */
         if (boundfaces(mesh, 
                        incidenttets[i][0],
                        incidenttets[i][1],
                        incidenttets[i][2],
                        incidenttets[i][3],
                        boundfacelist,
                        &numboundfaces))
         {
             if (improvebehave.verbosity > 5)
             {
                 printf("incident tet %d/%d had %d boundary faces\n", i+1, numincident, numboundfaces);
             }
             
             /* this tet had at least one boundary face. do any
                of it's boundary faces contain the vertex in
                question? */
             for (j=0; j<numboundfaces; j++)
             {
                 if ((boundfacelist[j][0] == vtx) ||
                     (boundfacelist[j][1] == vtx) ||
                     (boundfacelist[j][2] == vtx))
                 {
                     /* this face is incident to the vertex in question. */
                     numfaces++;
                     
                     /* fetch the coordinates of the face vertices */
                     vc1 = ((struct vertex *) tetcomplextag2vertex(mesh, boundfacelist[j][0]))->coord;
                     vc2 = ((struct vertex *) tetcomplextag2vertex(mesh, boundfacelist[j][1]))->coord;
                     vc3 = ((struct vertex *) tetcomplextag2vertex(mesh, boundfacelist[j][2]))->coord;
                     
                     /* form two edge vectors for the face */
                     vsub(vc2, vc1, e1);
                     vsub(vc3, vc1, e2);
                     
                     /* find the (unit-length) face normal of this face */
                     cross(e1, e2, curnorm);
                     vscale((1.0 / vlength(curnorm)),curnorm, curnorm);
                     
                     /* if this is the first face we have found, establish it's
                        normal as the "reference normal" which future faces
                        will be tested against for coplanarity */
                     if (foundface == false)
                     {
                         foundface = true;
                         vcopy(curnorm, refnorm);
                     }
                     else
                     {
                        /* is the dot product of this normal within
                           COPLANARTOL of the reference normal? */
                        dotprod = dot(curnorm, refnorm);
                        
                        if ((dotprod > (1.0 + COPLANARTOL)) || (dotprod < (1.0 - COPLANARTOL)))
                        {
                            if (improvebehave.verbosity > 5)
                            {
                                printf("Vertex is not facet because dotprod = %g\n", dotprod);
                            }
                            
                            /* this new normal is not close enough to coplanar.
                               we know that this vertex cannot be a facet vertex */
                            return false;
                        }
                     }
                 }
             }
         }
         else
         {
             if (improvebehave.verbosity > 5)
             {
                 printf("the #%d/%d incident tet had no boundary faces\n", i+1, numincident);
             }
         }
     }
     
     /* if we get here having seen at least 3 coplanar faces, must be facet vertex */
     if (numfaces >= 3)
     {
         if (improvebehave.verbosity > 5)
         {
             printf("Found a face lying in an input facet surrounded by %d coplanar surface faces (last dotprod = %g).\n", numfaces, dotprod);
         }
         vcopy(refnorm,normal);
         return true;
     }
     
     if (improvebehave.verbosity > 5)
     {
         printf("found coplanar faces but only %d of them\n", numfaces);
     }
     return false;
}

/* given a boundary vertex and a list of all of it's
   incident tets, determine if it lies in an input segment */
bool segmentvertex(struct tetcomplex *mesh,
                    tag vtx,
                    tag incidenttets[][4],
                    int numincident,
                    starreal edge[3])
{
      int foundfaces=0;        /* how many incident boundary face so far? */
      tag boundfacelist[4][3]; /* list of boundary faces for a particular tet */
      int numboundfaces;       /* number of boundary faces  for a tet */
      starreal refnorm1[3] = {0.0, 0.0, 0.0};    /* "reference" normal of first face */
      starreal refnorm2[3] = {0.0, 0.0, 0.0};    /* the other reference plane */
      starreal curnorm[3];     /* the current face's normal */
      starreal e1[3], e2[3];   /* edges for forming cross products */
      starreal *vc1, *vc2, *vc3; /* coordinates of the face vertices */
      starreal dotprod=0.0;        /* dot product of current and reference normal */
      int numfaces=0;            /* total coplanar faces surrounding vertex */
      int i,j;

      /* first, check to see if we lie in a facet. to do this, we need
         to build a list of all the boundary faces incident to this vertex.
         this is the same as getting all of the boundary faces of all incident
         tets that include this vertex. */

      if (improvebehave.verbosity > 5)
      {
          printf("**** Starting search  for incident boundary faces of vertex %d ****\n", (int) vtx);
          printf("here is what the area around the vertex looks like:\n");
          printtets(mesh, incidenttets, numincident);
      }

      /* for each incident tet */
      for (i=0; i<numincident; i++)
      {
          /* collect all the boundary faces */
          if (boundfaces(mesh, 
                         incidenttets[i][0],
                         incidenttets[i][1],
                         incidenttets[i][2],
                         incidenttets[i][3],
                         boundfacelist,
                         &numboundfaces))
          {
              if (improvebehave.verbosity > 5)
              {
                  printf("incident tet %d/%d had %d boundary faces\n", i+1, numincident, numboundfaces);
              }

              /* this tet had at least one boundary face. do any
                 of it's boundary faces contain the vertex in
                 question? */
              for (j=0; j<numboundfaces; j++)
              {
                  if ((boundfacelist[j][0] == vtx) ||
                      (boundfacelist[j][1] == vtx) ||
                      (boundfacelist[j][2] == vtx))
                  {
                      /* this face is incident to the vertex in question. */
                      numfaces++;

                      /* fetch the coordinates of the face vertices */
                      vc1 = ((struct vertex *) tetcomplextag2vertex(mesh, boundfacelist[j][0]))->coord;
                      vc2 = ((struct vertex *) tetcomplextag2vertex(mesh, boundfacelist[j][1]))->coord;
                      vc3 = ((struct vertex *) tetcomplextag2vertex(mesh, boundfacelist[j][2]))->coord;

                      /* form two edge vectors for the face */
                      vsub(vc2, vc1, e1);
                      vsub(vc3, vc1, e2);

                      /* find the (unit-length) face normal of this face */
                      cross(e1, e2, curnorm);
                      vscale((1.0 / vlength(curnorm)),curnorm, curnorm);

                      /* if this is the first face we have found, establish it's
                         normal as the "reference normal" which future faces
                         will be tested against for coplanarity */
                      if (foundfaces == 0)
                      {
                          foundfaces = 1;
                          vcopy(curnorm, refnorm1);
                      }
                      else
                      {
                         /* is the dot product of this normal within
                            COPLANARTOL of the first reference normal? */
                         dotprod = dot(curnorm, refnorm1);

                         /* do dot products match for first normal? */
                         if ((dotprod > (1.0 + COPLANARTOL)) || (dotprod < (1.0 - COPLANARTOL)))
                         {
                             /* nope. is there a second reference yet? */
                             if (foundfaces == 1)
                             {
                                 /* no second reference yet. make this it */
                                 foundfaces = 2;
                                 vcopy(curnorm, refnorm2);
                             }
                             else
                             {
                                 dotprod = dot(curnorm, refnorm2);
                                 if ((dotprod > (1.0 + COPLANARTOL)) || (dotprod < (1.0 - COPLANARTOL)))
                                 {
                                     if (improvebehave.verbosity > 5)
                                     {
                                         printf("curnorm = %g %g %g wasn't close enough to refnorm1 %g %g %g or refnorm2 %g %g %g\n", curnorm[0], 
                                                                                                                                      curnorm[1], 
                                                                                                                                      curnorm[2],
                                                                                                                                      refnorm1[0],
                                                                                                                                      refnorm1[1],
                                                                                                                                      refnorm1[2],
                                                                                                                                      refnorm1[0],
                                                                                                                                      refnorm1[1],
                                                                                                                                      refnorm1[2]);
                                     }
                                     /* this normal doesn't match either of the references */
                                     return false;
                                 }
                             }
                         }
                      }
                  }
              }
          }
          else
          {
              if (improvebehave.verbosity > 5)
              {
                  printf("the #%d/%d incident tet had no boundary faces\n", i+1, numincident);
              }
          }
      }

      /* if we get here having seen at least 3 faces, must be segment vertex */
      if (numfaces >= 3)
      {
          if (improvebehave.verbosity > 5)
          {
              printf("Found a vertex lying in an input segment surrounded by %d surface faces (last dotprod = %g).\n", numfaces, dotprod);
              /*
              printtets(mesh, incidenttets, numincident);
              */
          }
          /* the segment that this vertex lies on is perpendicular to both reference normals */
          cross(refnorm1, refnorm2, edge);
          return true;
      }
      return false;
}

/* given a tet, classifies each of its vertices according to how many
   degrees of freedom it has. TODO: The starter code was copied from boundverts(),
   could these two be combined? */
void tetvertexclassify(struct tetcomplex *mesh,
                       tag v1,
                       tag v2,
                       tag v3,
                       tag v4)
{
    int i,j,k,l;   /* loop indices */
    bool noghosts; /* any ghost tets incident to this vertex? */
    tag tet[4];
    int numincident;               /* number of incident tets */
    starreal facetnormal[3];
    starreal segmentedge[3];
    struct vertextype* info;
    struct vertextype* vptr;
    tag inverts[1];
    
    /* a list of all the tets incident to this vertex */
    tag incidenttettags[MAXINCIDENTTETS][4];
    
    tet[0] = v1;
    tet[1] = v2;
    tet[2] = v3;
    tet[3] = v4;
    
    /* check each vertex */
    for (i = 0; i < 4; i++) 
    {
        j = (i + 1) & 3;
        if ((i & 1) == 0) {
            l = (i + 3) & 3;
            k = (i + 2) & 3;
        } else {
            l = (i + 2) & 3;
            k = (i + 3) & 3;
        }
        
        /* check whether this vertex has already been classified */
        vptr = (struct vertextype *) arraypoollookup(&vertexinfo, tet[i]);
        assert(vptr != NULL);
        /* it's not null. is it zero (unset?) */
        if (vptr->kind != INPUTVERTEX)
        {
            /* we've already classified this vertex, move on */
            if (improvebehave.verbosity > 5)
            {
                printf("skipping reclassification of vertex %d\n", (int) tet[i]);
            }
            continue;
        }
        
        if (improvebehave.verbosity > 5)
        {
            printf("actually trying to classify vertex %d\n", (int) tet[i]);
        }
        
        /* get all the tets incident to this vertex. */
        numincident = 0;
        noghosts = true;
        getincidenttets(mesh, 
                        tet[i],
                        tet[j],
                        tet[k],
                        tet[l], 
                        incidenttettags,
                        &numincident,
                        &noghosts);
        
        /* is this a boundary vertex? */
        if (noghosts)
        {
            /* this vertex is in the interior of the mesh and so is free
               to move in three dimensions. Assign it the type FREEVERTEX */
            ((struct vertextype *) arraypoolforcelookup(&vertexinfo, tet[i]))->kind = FREEVERTEX;
            
            /* save this assignment in the journal */
            inverts[0] = tet[i];
            insertjournalentry(mesh, CLASSIFY, inverts, FREEVERTEX, NULL, facetnormal);
        }
        else
        {
            /* this vertex could still have freedom to move if it lies in a
               facet or along a segment. first, is it in a facet? */
            if (facetvertex(mesh, tet[i], incidenttettags, numincident, facetnormal))
            {
                /* mark this vertex as a facet and save the facet normal */
                info = (struct vertextype *) arraypoolforcelookup(&vertexinfo, tet[i]);
                info->kind = FACETVERTEX;
                vcopy(facetnormal,info->vec);
                
                /* save this assignment in the journal */
                inverts[0] = tet[i];
                insertjournalentry(mesh, CLASSIFY, inverts, FACETVERTEX, NULL, facetnormal);
            }
            else
            {
                /* check to see if this is a segment vertex */
                if (segmentvertex(mesh, tet[i], incidenttettags, numincident, segmentedge))
                {
                    /* mark this vertex as a segment vertex */
                    info = (struct vertextype *) arraypoolforcelookup(&vertexinfo, tet[i]);
                    info->kind = SEGMENTVERTEX;
                    vcopy(segmentedge,info->vec);
                    
                    /* save this assignment in the journal */
                    inverts[0] = tet[i];
                    insertjournalentry(mesh, CLASSIFY, inverts, SEGMENTVERTEX, NULL, segmentedge);
                }
                /* this vertex can't go anywhere */
                else
                {
                    info = (struct vertextype *) arraypoolforcelookup(&vertexinfo, tet[i]);
                    info->kind = FIXEDVERTEX;
                    
                    /* save this assignment in the journal */
                    inverts[0] = tet[i];
                    insertjournalentry(mesh, CLASSIFY, inverts, FIXEDVERTEX, NULL, segmentedge);
                }
            }
        }
        
    }
}

/* classify the number of degrees of freedom for all tets in the mesh */
void classifyvertices(struct tetcomplex *mesh)
{
    struct arraypoolstack tetstack;   /* stack of tets  */
    struct arraypoolstack localstack; /* local stack of tets that includes only one per vertex */
    struct improvetet * stacktet;     /* tet we're pulling off the stack */
    struct improvetet * localtet;
    int i;
    starreal minqual, meanqual[NUMMEANTHRESHOLDS];
    
    stackinit(&tetstack, sizeof(struct improvetet));
    
    /* fill the stack of tets with all tets in the mesh */
    fillstackqual(mesh, &tetstack, improvebehave.qualmeasure, HUGEFLOAT, meanqual, &minqual);
    
    /* initialize the tet stack */
    stackinit(&localstack, sizeof(struct improvetet));
    
    /* try to pop all the tets off the stack */
    while (tetstack.top != STACKEMPTY)
    {
        /* pull the top tet off the stack */
        stacktet = (struct improvetet *) stackpop(&tetstack);
        
        if (improvebehave.verbosity > 5 && localstack.top % 10000 == 0)
        {
            printf("tetstack size now %lu, localstack size is %lu\n", tetstack.top, localstack.top);
        }

        /* push this tet on the local stack */
        localtet = (struct improvetet *) stackpush(&localstack);
        /* copy tet over */
        localtet->verts[0] = stacktet->verts[0];
        localtet->verts[1] = stacktet->verts[1];
        localtet->verts[2] = stacktet->verts[2];
        localtet->verts[3] = stacktet->verts[3];
        localtet->quality = stacktet->quality;
        
        /* force initialization of vertex type for all vertices of this tet to INPUTVERTEX */
        for (i=0; i<4; i++)
        {
            ((struct vertextype *) arraypoolforcelookup(&vertexinfo, stacktet->verts[i]))->kind = INPUTVERTEX;
        }
    }
   
    if (improvebehave.verbosity > 4)
    {
        printf("Done creating initial stack of verts for classification of size %lu\n", localstack.top);
    }
 
    /* go through each tet on the stack */
    while (localstack.top != STACKEMPTY)
    {
        /* pull the top tet off the stack */
        stacktet = (struct improvetet *) stackpop(&localstack);
        
        if (improvebehave.verbosity > 5 && localstack.top % 10000 == 0)
        {
            printf("localstack emptying, now size %lu\n", localstack.top);
        }

        /* assign freedom for vertices in this tet */
        tetvertexclassify(mesh,
                          stacktet->verts[0], 
                          stacktet->verts[1], 
                          stacktet->verts[2], 
                          stacktet->verts[3]);
    }
}



<|start_filename|>vtkVmtk/Segmentation/vtkvmtkDanielssonDistanceMapImageFilter.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkDanielssonDistanceMapImageFilter.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkDanielssonDistanceMapImageFilter.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkITKFilterUtilities.h"

#include "itkDanielssonDistanceMapImageFilter.h"

vtkStandardNewMacro(vtkvmtkDanielssonDistanceMapImageFilter);

vtkvmtkDanielssonDistanceMapImageFilter::vtkvmtkDanielssonDistanceMapImageFilter()
{
  this->SquaredDistance = 0;
  this->InputIsBinary = 0;
}

void vtkvmtkDanielssonDistanceMapImageFilter::SimpleExecute(vtkImageData* input, vtkImageData* output)
{
  typedef itk::Image<float,3> ImageType;

  ImageType::Pointer inImage = ImageType::New();

  vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(input,inImage);

  typedef itk::DanielssonDistanceMapImageFilter<ImageType, ImageType> DanielssonFilterType;

  DanielssonFilterType::Pointer danielssonFilter = DanielssonFilterType::New();
  danielssonFilter->SetInput(inImage);
  danielssonFilter->SetSquaredDistance(this->SquaredDistance);
  danielssonFilter->SetInputIsBinary(this->InputIsBinary);
  danielssonFilter->Update();

  vtkvmtkITKFilterUtilities::ITKToVTKImage<ImageType>(danielssonFilter->GetOutput(),output);
}



<|start_filename|>vtkVmtk/Segmentation/vtkvmtkActiveTubeFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: .h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkActiveTubeFilter - Experimental method for generating centerlines from an image.
// .SECTION Description
// Developed with support from the EC FP7/2007-2013: ARCH, Project n. 224390

#ifndef __vtkvmtkActiveTubeFilter_h
#define __vtkvmtkActiveTubeFilter_h

#include "vtkPolyDataAlgorithm.h"
#include "vtkvmtkWin32Header.h"

class vtkImageData;
class vtkDoubleArray;

class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkActiveTubeFilter : public vtkPolyDataAlgorithm
{
  public: 
  vtkTypeMacro(vtkvmtkActiveTubeFilter,vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkActiveTubeFilter *New();

  virtual void SetPotentialImage(vtkImageData *);
  vtkGetObjectMacro(PotentialImage, vtkImageData);

  vtkSetStringMacro(RadiusArrayName);
  vtkGetStringMacro(RadiusArrayName);

  vtkSetMacro(NumberOfIterations,int);
  vtkGetMacro(NumberOfIterations,int);

  vtkSetMacro(PotentialWeight,double);
  vtkGetMacro(PotentialWeight,double);

  vtkSetMacro(StiffnessWeight,double);
  vtkGetMacro(StiffnessWeight,double);

  vtkSetMacro(Convergence,double);
  vtkGetMacro(Convergence,double);

  vtkSetMacro(CFLCoefficient,double);
  vtkGetMacro(CFLCoefficient,double);
 
  vtkSetMacro(MinimumRadius,double);
  vtkGetMacro(MinimumRadius,double);
 
  vtkSetMacro(FixedEndpointCoordinates,int);
  vtkGetMacro(FixedEndpointCoordinates,int);
  vtkBooleanMacro(FixedEndpointCoordinates,int);
 
  vtkSetMacro(FixedEndpointRadius,int);
  vtkGetMacro(FixedEndpointRadius,int);
  vtkBooleanMacro(FixedEndpointRadius,int);
 
  vtkSetMacro(NumberOfAngularEvaluations,int);
  vtkGetMacro(NumberOfAngularEvaluations,int);
 
  vtkSetMacro(SplineResamplingWhileIterating,int);
  vtkGetMacro(SplineResamplingWhileIterating,int);
  vtkBooleanMacro(SplineResamplingWhileIterating,int);
 
  vtkSetMacro(NegativeNormWarnings,int);
  vtkGetMacro(NegativeNormWarnings,int);
  vtkBooleanMacro(NegativeNormWarnings,int);
 
  protected:
  vtkvmtkActiveTubeFilter();
  ~vtkvmtkActiveTubeFilter();  

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  void EvaluateForce(double point[3], double force[3], bool normalize);
  double EvaluatePotential(double point[3]);

  static bool IsInExtent(vtkIdType extent[6], int ijk[3], vtkIdType border)
    {
    return (ijk[0]>=extent[0]+border && ijk[0]<=extent[1]-border) && (ijk[1]>=extent[2]+border && ijk[1]<=extent[3]-border) && (ijk[2]>=extent[4]+border && ijk[2]<=extent[5]-border) ? true : false;
    }

  static bool IsCellInExtent(int extent[6], int ijk[3], vtkIdType border)
    {
    return (ijk[0]>=extent[0]+border && ijk[0]<extent[1]-border) && (ijk[1]>=extent[2]+border && ijk[1]<extent[3]-border) && (ijk[2]>=extent[4]+border && ijk[2]<extent[5]-border) ? true : false;
    }

  void EvolveCellSpline(vtkPolyData* lines, vtkIdType cellId);

  char* RadiusArrayName;

  vtkImageData *PotentialImage;
  vtkImageData *PotentialGradientImage;

  int NumberOfIterations;
  int NumberOfAngularEvaluations;

  double CFLCoefficient;
  double Convergence;

  double PotentialWeight;
  double StiffnessWeight;

  double MinimumRadius;

  double PotentialMaxNorm;

  int FixedEndpointCoordinates;
  int FixedEndpointRadius;

  int SplineResamplingWhileIterating;

  bool NegativeNormWarnings;

private:
  vtkvmtkActiveTubeFilter(const vtkvmtkActiveTubeFilter&);  // Not implemented.
  void operator=(const vtkvmtkActiveTubeFilter&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/Segmentation/vtkvmtkSigmoidImageFilter.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkbvsSigmoidImageFilter.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkSigmoidImageFilter.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkITKFilterUtilities.h"

#include "itkSigmoidImageFilter.h"

vtkStandardNewMacro(vtkvmtkSigmoidImageFilter);

vtkvmtkSigmoidImageFilter::vtkvmtkSigmoidImageFilter()
{
  this->Alpha = 1.0;
  this->Beta = 1.0;
  this->OutputMinimum = 0.0;
  this->OutputMaximum = 1.0;
}

void vtkvmtkSigmoidImageFilter::SimpleExecute(vtkImageData* input, vtkImageData* output)
{
  typedef itk::Image<float,3> ImageType;

  ImageType::Pointer inImage = ImageType::New();

  vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(input,inImage);

  typedef itk::SigmoidImageFilter<ImageType,ImageType> SigmoidFilterType;

  SigmoidFilterType::Pointer sigmoidFilter = SigmoidFilterType::New();
  sigmoidFilter->SetInput(inImage);
  sigmoidFilter->SetAlpha(this->Alpha);
  sigmoidFilter->SetBeta(this->Beta);
  sigmoidFilter->SetOutputMinimum(this->OutputMinimum);
  sigmoidFilter->SetOutputMaximum(this->OutputMaximum);
  sigmoidFilter->Update();

  vtkvmtkITKFilterUtilities::ITKToVTKImage<ImageType>(sigmoidFilter->GetOutput(),output);
}



<|start_filename|>vtkVmtk/Segmentation/vtkvmtkSigmoidImageFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkSigmoidImageFilter.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.3 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkSigmoidImageFilter - Wrapper class around itk::SigmoidImageFilter
// .SECTION Description
// vtkvmtkSigmoidImageFilter


#ifndef __vtkvmtkSigmoidImageFilter_h
#define __vtkvmtkSigmoidImageFilter_h

#include "vtkSimpleImageToImageFilter.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkSigmoidImageFilter : public vtkSimpleImageToImageFilter
{
 public:
  static vtkvmtkSigmoidImageFilter *New();
  vtkTypeMacro(vtkvmtkSigmoidImageFilter, vtkSimpleImageToImageFilter);

  vtkGetMacro(Alpha,double);
  vtkSetMacro(Alpha,double);

  vtkGetMacro(Beta,double);
  vtkSetMacro(Beta,double);

  vtkGetMacro(OutputMinimum,double);
  vtkSetMacro(OutputMinimum,double);

  vtkGetMacro(OutputMaximum,double);
  vtkSetMacro(OutputMaximum,double);

protected:

  vtkvmtkSigmoidImageFilter();
  ~vtkvmtkSigmoidImageFilter() {};

  virtual void SimpleExecute(vtkImageData* input, vtkImageData* output) VTK_OVERRIDE;

private:
  vtkvmtkSigmoidImageFilter(const vtkvmtkSigmoidImageFilter&);  // Not implemented.
  void operator=(const vtkvmtkSigmoidImageFilter&);  // Not implemented.

  double Alpha;
  double Beta;
  double OutputMinimum;
  double OutputMaximum;
};

#endif






<|start_filename|>CMake/CMakeOptions.cmake<|end_filename|>
#
# Configure output paths for libraries and executables.
#
set(LIBRARY_OUTPUT_PATH ${VTK_VMTK_BINARY_DIR}/bin CACHE PATH
    "Single output directory for building all libraries.")
set(EXECUTABLE_OUTPUT_PATH ${VTK_VMTK_BINARY_DIR}/bin CACHE PATH
    "Single output directory for building all executables.")
mark_as_advanced(LIBRARY_OUTPUT_PATH EXECUTABLE_OUTPUT_PATH)

#
# Try to find VTK and include its settings (otherwise complain)
#
if ( NOT VTK_FOUND )
  find_package(VTK REQUIRED)
  include(${VTK_USE_FILE})
endif ( NOT VTK_FOUND )

#
# Try to find ITK and include its settings (otherwise complain)
#
if ( NOT ITK_FOUND )
  find_package(ITK REQUIRED)
  include(${ITK_USE_FILE})
endif ( NOT ITK_FOUND )

#
# Build shared libs ?
#
# Defaults to the same VTK setting.
#

# Standard CMake option for building libraries shared or static by default.
option(BUILD_SHARED_LIBS
       "Build with shared libraries."
       ${VTK_BUILD_SHARED_LIBS})
# Copy the CMake option to a setting with VTK_VMTK_ prefix for use in
# our project.  This name is used in vtkvmtkConfigure.h.in.
set(VTK_VMTK_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})

# If this is a build tree, provide an option for putting
# this project's executables and libraries in with VTK's.
if (EXISTS ${VTK_DIR}/bin)
  option(USE_VTK_OUTPUT_PATHS
         "Use VTK's output directory for this project's executables and libraries."
         OFF)
  mark_as_advanced (USE_VTK_OUTPUT_PATHS)
  if (USE_VTK_OUTPUT_PATHS)
    set (LIBRARY_OUTPUT_PATH ${VTK_DIR}/bin)
    set (EXECUTABLE_OUTPUT_PATH ${VTK_DIR}/bin)
  endif (USE_VTK_OUTPUT_PATHS)
endif (EXISTS ${VTK_DIR}/bin)


#
# Wrap Tcl, Java, Python
#
# Rational: even if your VTK was wrapped, it does not mean that you want to
# wrap your own local classes.
# Default value is OFF as the VTK cache might have set them to ON but
# the wrappers might not be present (or yet not found).
#

#
# Python
#

if (VTK_WRAP_PYTHON)

  option(VTK_VMTK_WRAP_PYTHON
         "Wrap classes into the Python interpreted language."
         ON)

  if (VTK_VMTK_WRAP_PYTHON)
    set(VTK_WRAP_PYTHON3_INIT_DIR "${VTK_VMTK_SOURCE_DIR}/Wrapping")
    include(${VTK_CMAKE_DIR}/vtkWrapPython.cmake)
    if (WIN32)
      if (NOT BUILD_SHARED_LIBS)
        message(FATAL_ERROR "Python support requires BUILD_SHARED_LIBS to be ON.")
        set (VTK_VMTK_CAN_BUILD 0)
      endif (NOT BUILD_SHARED_LIBS)
    endif (WIN32)
  endif (VTK_VMTK_WRAP_PYTHON)

else (VTK_WRAP_PYTHON)

  if (VTK_VMTK_WRAP_PYTHON)
    message("Warning. VTK_VMTK_WRAP_PYTHON is ON but the VTK version you have "
            "chosen has not support for Python (VTK_WRAP_PYTHON is OFF).  "
            "Please set VTK_VMTK_WRAP_PYTHON to OFF.")
    set (VTK_VMTK_WRAP_PYTHON OFF)
  endif (VTK_VMTK_WRAP_PYTHON)

endif (VTK_WRAP_PYTHON)

#
# Java
#

if (VTK_WRAP_JAVA)

  option(VTK_VMTK_WRAP_JAVA
         "Wrap classes into the Java interpreted language."
         ON)

  if (VTK_VMTK_WRAP_JAVA)
    set(VTK_WRAP_JAVA3_INIT_DIR "${VTK_VMTK_SOURCE_DIR}/Wrapping")
    include(${VTK_CMAKE_DIR}/vtkWrapJava.cmake)
    if (WIN32)
      if (NOT BUILD_SHARED_LIBS)
        message(FATAL_ERROR "Java support requires BUILD_SHARED_LIBS to be ON.")
        set (VTK_VMTK_CAN_BUILD 0)
      endif (NOT BUILD_SHARED_LIBS)
    endif (WIN32)

    # Tell the java wrappers where to go.
    set(VTK_JAVA_HOME ${VTK_VMTK_BINARY_DIR}/java/vtkvmtk)
    MAKE_DIRECTORY(${VTK_JAVA_HOME})
  endif (VTK_VMTK_WRAP_JAVA)

else (VTK_WRAP_JAVA)

  if (VTK_VMTK_WRAP_JAVA)
    message("Warning. VTK_VMTK_WRAP_JAVA is ON but the VTK version you have "
            "chosen has not support for Java (VTK_WRAP_JAVA is OFF).  "
            "Please set VTK_VMTK_WRAP_JAVA to OFF.")
    set (VTK_VMTK_WRAP_JAVA OFF)
  endif (VTK_VMTK_WRAP_JAVA)

endif (VTK_WRAP_JAVA)

# setup our local hints file in case wrappers need them.
set(VTK_WRAP_HINTS ${VTK_VMTK_SOURCE_DIR}/Wrapping/hints)


<|start_filename|>vtkVmtk/Segmentation/vtkvmtkVesselEnhancingDiffusionImageFilter.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkbvsVesselEnhancingDiffusionImageFilter.cxx,v $
Language:  C++
Date:      $Date: 2006/04/06 16:48:25 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

  Portions of this code are covered under the ITK copyright.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkVesselEnhancingDiffusionImageFilter.h"
#include "vtkObjectFactory.h"

#include "vtkvmtkITKFilterUtilities.h"

#include "itkAnisotropicDiffusionVesselEnhancementImageFilter.h"
#include "itkMultiScaleHessianBasedMeasureImageFilter.h"
#include "itkHessianSmoothed3DToVesselnessMeasureImageFilter.h"

vtkStandardNewMacro(vtkvmtkVesselEnhancingDiffusionImageFilter);

vtkvmtkVesselEnhancingDiffusionImageFilter::vtkvmtkVesselEnhancingDiffusionImageFilter()
{
  this->SigmaMin = 1.0;
  this->SigmaMax = 1.0;
  this->NumberOfSigmaSteps = 1;
  this->SigmaStepMethod = EQUISPACED;
  this->NumberOfIterations = 1;
  this->NumberOfDiffusionSubIterations = 1;
  this->TimeStep = 0.01;
  this->Epsilon = 1E-6;
  this->WStrength = 1.0;
  this->Sensitivity = 1.0;
  this->Alpha = 1.0;
  this->Beta = 1.0;
  this->Gamma = 1.0;
  this->C = 1.0;
}

void vtkvmtkVesselEnhancingDiffusionImageFilter::SimpleExecute(vtkImageData* input, vtkImageData* output)
{
  typedef itk::Image<float,3> ImageType;

  ImageType::Pointer inImage = ImageType::New();

  vtkvmtkITKFilterUtilities::VTKToITKImage<ImageType>(input,inImage);

  typedef itk::AnisotropicDiffusionVesselEnhancementImageFilter<ImageType, ImageType> AnisotropicDiffusionFilterType;
  typedef AnisotropicDiffusionFilterType::MultiScaleVesselnessFilterType MultiScaleFilterType;
  typedef AnisotropicDiffusionFilterType::VesselnessFilterType VesselnessFilterType;

  AnisotropicDiffusionFilterType::Pointer anisotropicDiffusionFilter = AnisotropicDiffusionFilterType::New();

  MultiScaleFilterType::Pointer multiScaleFilter = anisotropicDiffusionFilter->GetMultiScaleVesselnessFilter();
  multiScaleFilter->SetSigmaMinimum(this->SigmaMin);
  multiScaleFilter->SetSigmaMaximum(this->SigmaMax);
  multiScaleFilter->SetNumberOfSigmaSteps(this->NumberOfSigmaSteps);
  if (this->SigmaStepMethod == EQUISPACED)
    {
      multiScaleFilter->SetSigmaStepMethodToEquispaced();
    }
  else if (this->SigmaStepMethod == LOGARITHMIC)
    {
      multiScaleFilter->SetSigmaStepMethodToLogarithmic();
    }

  VesselnessFilterType* vesselnessFilter = dynamic_cast<VesselnessFilterType*>(multiScaleFilter->GetHessianToMeasureFilter());
  vesselnessFilter->SetAlpha(this->Alpha);
  vesselnessFilter->SetBeta(this->Beta);
  vesselnessFilter->SetGamma(this->Gamma);
  vesselnessFilter->SetC(this->C);

  anisotropicDiffusionFilter->SetInput(inImage);
  anisotropicDiffusionFilter->SetTimeStep(this->TimeStep);
  anisotropicDiffusionFilter->SetEpsilon(this->Epsilon);
  anisotropicDiffusionFilter->SetWStrength(this->WStrength);
  anisotropicDiffusionFilter->SetSensitivity(this->Sensitivity);
  anisotropicDiffusionFilter->SetNumberOfIterations(this->NumberOfIterations);
  anisotropicDiffusionFilter->SetNumberOfDiffusionSubIterations(this->NumberOfDiffusionSubIterations);
  anisotropicDiffusionFilter->Update();

  vtkvmtkITKFilterUtilities::ITKToVTKImage<ImageType>(anisotropicDiffusionFilter->GetOutput(),output);
}



<|start_filename|>vtkVmtk/DifferentialGeometry/vtkvmtkStencils.h<|end_filename|>
/*=========================================================================

  Program:   VMTK
  Module:    $RCSfile: vtkvmtkStencils.h,v $
  Language:  C++
  Date:      $Date: 2006/04/06 16:46:44 $
  Version:   $Revision: 1.4 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkStencils - Create an empty, umbrella, area weighted umbrella, finite-element LP, or finite-volume finite-element stencil for a particular data set.
// .SECTION Description
// ..

#ifndef __vtkvmtkStencils_h
#define __vtkvmtkStencils_h

#include "vtkObject.h"
#include "vtkvmtkConstants.h"
#include "vtkvmtkDataSetItems.h"
#include "vtkvmtkStencil.h"
#include "vtkDataSet.h"
//#include "vtkvmtkDifferentialGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"

class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkStencils : public vtkvmtkDataSetItems 
{
public:

  static vtkvmtkStencils* New();
  vtkTypeMacro(vtkvmtkStencils,vtkvmtkItems);

  void SetStencilTypeToEmptyStencil()
    {this->SetItemType(VTK_VMTK_EMPTY_STENCIL);};  
  void SetStencilTypeToUmbrellaStencil()
    {this->SetItemType(VTK_VMTK_UMBRELLA_STENCIL);};  
  void SetStencilTypeToAreaWeightedUmbrellaStencil()
    {this->SetItemType(VTK_VMTK_AREA_WEIGHTED_UMBRELLA_STENCIL);};  
  void SetStencilTypeToFELaplaceBeltramiStencil()
    {this->SetItemType(VTK_VMTK_FE_LAPLACE_BELTRAMI_STENCIL);};  
  void SetStencilTypeToFVFELaplaceBeltramiStencil()
    {this->SetItemType(VTK_VMTK_FVFE_LAPLACE_BELTRAMI_STENCIL);};
  void SetStencilTypeToGradientStencil()
    {this->SetItemType(VTK_VMTK_GRADIENT_STENCIL);};  

  // Description:
  // Get a stencil given a point id.
  vtkvmtkStencil* GetStencil(vtkIdType ptId) {return (vtkvmtkStencil*)this->Array[ptId];};

  void SetNumberOfStencils(vtkIdType numberOfStencils) { this->SetNumberOfItems(numberOfStencils);};
  vtkIdType GetNumberOfStencils() {return this->GetNumberOfItems();};

  void AllocateStencil(vtkIdType i, vtkIdType stencilType) {this->AllocateItem(i,stencilType);};

  vtkSetMacro(WeightScaling,int)
  vtkGetMacro(WeightScaling,int)
  vtkBooleanMacro(WeightScaling,int)

  vtkSetMacro(NegateWeights,int)
  vtkGetMacro(NegateWeights,int)
  vtkBooleanMacro(NegateWeights,int)

protected:
  vtkvmtkStencils();
  ~vtkvmtkStencils() {};

  virtual vtkvmtkItem* InstantiateNewItem(int itemType) VTK_OVERRIDE;

  int WeightScaling;

  int NegateWeights;
  
private:
  vtkvmtkStencils(const vtkvmtkStencils&);  // Not implemented.
  void operator=(const vtkvmtkStencils&);  // Not implemented.
};

#endif



<|start_filename|>vtkVmtk/Misc/vtkvmtkUnstructuredGridTetraFilter.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkUnstructuredGridTetraFilter.h,v $
Language:  C++
Date:      $Date: 2006/07/17 09:53:14 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
  // .NAME vtkvmtkUnstructuredGridTetraFilter - Convert the elements of a mesh to linear tetrahedra.
  // .SECTION Description
  // .

#ifndef __vtkvmtkUnstructuredGridTetraFilter_h
#define __vtkvmtkUnstructuredGridTetraFilter_h

#include "vtkUnstructuredGridAlgorithm.h"
#include "vtkvmtkWin32Header.h"

class vtkOrderedTriangulator;
class vtkIdList;

class VTK_VMTK_MISC_EXPORT vtkvmtkUnstructuredGridTetraFilter : public vtkUnstructuredGridAlgorithm
{
public:
  static vtkvmtkUnstructuredGridTetraFilter *New();
  vtkTypeMacro(vtkvmtkUnstructuredGridTetraFilter,vtkUnstructuredGridAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE;

  vtkSetMacro(TetrahedraOnly, int);
  vtkGetMacro(TetrahedraOnly, int);
  vtkBooleanMacro(TetrahedraOnly, int);

protected:
  vtkvmtkUnstructuredGridTetraFilter();
  ~vtkvmtkUnstructuredGridTetraFilter();

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) VTK_OVERRIDE;

  int TriangulateQuad(vtkUnstructuredGrid* output, vtkIdList *quadPtIds, vtkIdList *ptIds);

  vtkOrderedTriangulator *Triangulator;

  void Execute(vtkUnstructuredGrid *, vtkUnstructuredGrid *);

  int TetrahedraOnly;

private:
  vtkvmtkUnstructuredGridTetraFilter(const vtkvmtkUnstructuredGridTetraFilter&);  // Not implemented.
  void operator=(const vtkvmtkUnstructuredGridTetraFilter&);  // Not implemented.
};

#endif



<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/print.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*  printing utility functions                                               */
/*                                                                           */
/*****************************************************************************/

/* print the coordinates of the for vertices of a tet for viz purposes
   (prints them in the format of a MATLAB matrix, my ghetto viz tool) */
void printtetverts(struct tetcomplex *mesh, tag *tet)
{
    starreal *point[4];
    int i;
    
    /* get tet vertices */
    point[0] = ((struct vertex *) tetcomplextag2vertex(mesh, tet[0]))->coord;
    point[1] = ((struct vertex *) tetcomplextag2vertex(mesh, tet[1]))->coord;
    point[2] = ((struct vertex *) tetcomplextag2vertex(mesh, tet[2]))->coord;
    point[3] = ((struct vertex *) tetcomplextag2vertex(mesh, tet[3]))->coord;
    
    printf("[");
    for (i=0; i<4; i++)
    {
        printf("%f %f %f", point[i][0], point[i][1], point[i][2]);
        if (i != 3)
        {
            printf(";\n");
        }
    }
    printf("]");
}

/* print the geometric locations of face vertices */
void printfaceverts(struct tetcomplex *mesh, tag *face)
{
    starreal *point[4];
    int i;
    
    /* get tet vertices */
    point[0] = ((struct vertex *) tetcomplextag2vertex(mesh, face[0]))->coord;
    point[1] = ((struct vertex *) tetcomplextag2vertex(mesh, face[1]))->coord;
    point[2] = ((struct vertex *) tetcomplextag2vertex(mesh, face[2]))->coord;
    
    printf("[");
    for (i=0; i<3; i++)
    {
        printf("%f %f %f", point[i][0], point[i][1], point[i][2]);
        if (i != 3)
        {
            printf(";\n");
        }
    }
    printf("]");
}

/* another function that prints a tet with separate vertex args */
void printtetvertssep(struct tetcomplex *mesh,
                      tag vtx1,
                      tag vtx2,
                      tag vtx3,
                      tag vtx4)
{
    tag tet[4];
    tet[0] = vtx1;
    tet[1] = vtx2;
    tet[2] = vtx3;
    tet[3] = vtx4;
    
    printtetverts(mesh, tet);
}

/* print out an array of tets */
void printtets(struct tetcomplex *mesh,
               tag tets[][4],
               int numtets)
{
    int i; /* loop counter */
    
    printf("{");
    for (i=0; i<numtets; i++)
    {
        printtetverts(mesh, tets[i]);
        if (i != numtets-1)
        {
            printf(",\n");
        }
    }
    printf("};\n");
}

/* print out an array of tets */
void printopttets(struct tetcomplex *mesh,
                  struct opttet tets[],
                  int numtets)
{
    int i; /* loop counter */
    
    printf("{");
    for (i=0; i<numtets; i++)
    {
        printtetverts(mesh, tets[i].verts);
        if (i != numtets-1)
        {
            printf(",\n");
        }
    }
    printf("};\n");
}

/* print out an array of faces */
void printfaces(struct tetcomplex *mesh,
                tag faces[][3],
                int numfaces)
{
    int i; /* loop counter */
    
    printf("{");
    for (i=0; i<numfaces; i++)
    {
        printfaceverts(mesh, faces[i]);
        if (i != numfaces-1)
        {
            printf(",\n");
        }
    }
    printf("};\n");
}

/* print out an array of tets as tags*/
void printtetstags(tag tets[][4],
                   int numtets)
{
    int i; /* loop counter */
    
    printf("[");
    for (i=0; i<numtets; i++)
    {
        printf("%d %d %d %d;\n", (int) tets[i][0], (int) tets[i][1], (int) tets[i][2], (int) tets[i][3]);
    }
    printf("]\n");
}

/* print Q and K tables from Klincsek's algorithm for debugging
   purposes */
void printtables(starreal Q[][MAXRINGTETS],
                 int K[][MAXRINGTETS],
                 int ringcount)
{
    int i,j; /* loop counters */
    
    printf("*** Table Q ***\n");
    for (i=1; i<=ringcount; i++)
    {
        printf("[");
        for (j=1; j<=ringcount; j++)
        {
            printf("% f ", Q[i][j]);
        }
        printf("]\n");
    }
    
    printf("*** Table K ***\n");
    for (i=1; i<=ringcount; i++)
    {
        printf("[");
        for (j=1; j<=ringcount; j++)
        {
            printf("%2ul ", K[i][j]);
        }
        printf("]\n");
    }
}

/* print edge and ring around it for ghetto visualization in matlab */
void printring(struct tetcomplex *mesh, tag a, tag b, tag *ring, int ringcount)
{
    int i;
    tag tet[4];
    
    /* output every tet in the ring */
    printf("{\n");
    for (i=0; i<ringcount; i++)
    {
        tet[0] = ring[i];
        if (i == ringcount -1)
        {
            tet[1] = ring[0];
        }
        else
        {
            tet[1] = ring[i+1];
        }
        tet[2] = b;
        tet[3] = a;
        printtetverts(mesh, tet);
        if (i != ringcount -1)
        {
            printf(",\n");
        }
    }
    printf("}\n"); 
}

/* print edge and ring around it for ghetto visualization in matlab */
void printhalfring(struct tetcomplex *mesh, tag a, tag b, tag *ring, int ringcount)
{
    int i;
    tag tet[4];
    
    /* output every tet in the ring */
    printf("{");
    for (i=0; i<ringcount-1; i++)
    {
        tet[0] = ring[i];
        tet[1] = ring[i+1];
        tet[2] = b;
        tet[3] = a;
        /*
        printf("verts (%d %d %d %d)\n", tet[0], tet[1], tet[2], tet[3]);
        */
        printtetverts(mesh, tet);
        if (i != ringcount -2)
        {
            printf(",\n");
        }
    }
    printf("};\n"); 
}

/* print out the info in a opttet */
void printopttet(struct opttet *tet)
{
    int i,j;
    
    printf("For tet with verts (%d, %d, %d, %d):\n", (int) tet->verts[0], (int) tet->verts[1], (int) tet->verts[2], (int) tet->verts[3]);
    printf("    volume = %f\n", tet->volume);
    printf("    volume gradient = (%f, %f, %f)\n", tet->volumegrad[0], tet->volumegrad[1], tet->volumegrad[2]);
    printf("    edge lengths:\n");
    for (i=0; i<6; i++)
    {
        for (j = i + 1; j < 4; j++) 
        {            
            printf("        %d-%d: %f\n",i,j,tet->edgelength[i][j]);
        }
    }
    printf("    edge length graidents:\n");
    for (i=0; i<6; i++)
    {
        for (j = i + 1; j < 4; j++) 
        {
            printf("        %d-%d: %f %f %f\n",i,j,tet->edgegrad[i][j][0],tet->edgegrad[i][j][1],tet->edgegrad[i][j][2]);
        }
    }
    printf("    face areas:\n");
    for (i=0; i<4; i++)
    {
        printf("        %d: %f\n",i,tet->facearea[i]);
    }
    printf("    gradients of face areas:\n");
    for (i=0; i<4; i++)
    {
        printf("        %d: %f %f %f\n",i,tet->facegrad[i][0],tet->facegrad[i][1],tet->facegrad[i][2]);
    }
    printf("    sines of dihedral angles:\n");
    for (i=0; i<6; i++)
    {
        printf("        %d: %f\n",i,tet->sine[i]);
    }
    printf("    gradients of sines of dihedral angles:\n");
    for (i=0; i<6; i++)
    {
        printf("        %d: (%f, %f, %f)\n",i,tet->sinegrad[i][0],tet->sinegrad[i][1],tet->sinegrad[i][2]);
    }
}

/* print out B, S, M arrays from findbasis */
void printbasisarrays(starreal S[][3],
                      starreal M[][3],
                      starreal B[][3],
                      int sizeS,
                      int sizeM,
                      int *sizeB,
                      starreal p[])
{
    int i;
    
    printf("\nCurrent basis finding arrays:\n");
    printf("    p: %f %f %f\n",p[0],p[1],p[2]);
    printf("    S: [ ");
    for (i=0; i<sizeS; i++)
    {
        printf("(%f %f %f) ", S[i][0],S[i][1],S[i][2]);
    }
    printf("]\n");
    
    printf("    M: [ ");
    for (i=0; i<sizeM; i++)
    {
        printf("(%f %f %f) ", M[i][0],M[i][1],M[i][2]);
    }
    printf("]\n");
    
    printf("    B: [ ");
    for (i=0; i<*sizeB; i++)
    {
        printf("(%f %f %f) ", B[i][0],B[i][1],B[i][2]);
    }
    printf("]\n\n");
}

/* print out global improvement stats */
void printstatsstream(FILE *o, tetcomplex *mesh)
{
    int i, maxa, maxs, maxb, maxl;
    
#ifndef NO_TIMER
    struct timeval now;
    struct timezone tz;
#endif /* not NO_TIMER */

    fprintf(o, "Mesh Improvement Statistics:\n\n");
    
    /* smoothing */
    fprintf(o, "Smoothing statistics:\n");
    fprintf(o, "    Optimization smooths:    %d / %d\n", stats.nonsmoothsuccesses, stats.nonsmoothattempts);
    fprintf(o, "    Free vertex smooths:     %d / %d\n", stats.freesmoothsuccesses, stats.freesmoothattempts);
    fprintf(o, "    Facet vertex smooths:    %d / %d\n", stats.facetsmoothsuccesses, stats.facetsmoothattempts);
    fprintf(o, "    Segment vertex smooths:  %d / %d\n", stats.segmentsmoothsuccesses, stats.segmentsmoothattempts);
    fprintf(o, "    Fixed vertex smooths:    %d / %d\n", stats.fixedsmoothsuccesses, stats.fixedsmoothattempts);
    
    /* topological */
    fprintf(o, "\nTopological improvement statistics:\n");
    fprintf(o, "    Edge contractions:       %d / %d\n", stats.edgecontractions, stats.edgecontractionattempts);
    fprintf(o, "    Edge contraction cases:\n");
    fprintf(o, "        free-free            %d / %d\n", stats.edgecontractcasesuc[FREEFREEEDGE], stats.edgecontractcaseatt[FREEFREEEDGE]);
    fprintf(o, "        free-facet           %d / %d\n", stats.edgecontractcasesuc[FREEFACETEDGE], stats.edgecontractcaseatt[FREEFACETEDGE]);
    fprintf(o, "        free-segment         %d / %d\n", stats.edgecontractcasesuc[FREESEGMENTEDGE], stats.edgecontractcaseatt[FREESEGMENTEDGE]);
    fprintf(o, "        free-fixed           %d / %d\n", stats.edgecontractcasesuc[FREEFIXEDEDGE], stats.edgecontractcaseatt[FREEFIXEDEDGE]);
    fprintf(o, "        facet-facet          %d / %d\n", stats.edgecontractcasesuc[FACETFACETEDGE], stats.edgecontractcaseatt[FACETFACETEDGE]);
    fprintf(o, "        facet-segment        %d / %d\n", stats.edgecontractcasesuc[FACETSEGMENTEDGE], stats.edgecontractcaseatt[FACETSEGMENTEDGE]);
    fprintf(o, "        facet-fixed          %d / %d\n", stats.edgecontractcasesuc[FACETFIXEDEDGE], stats.edgecontractcaseatt[FACETFIXEDEDGE]);
    fprintf(o, "        segment-segment      %d / %d\n", stats.edgecontractcasesuc[SEGMENTSEGMENTEDGE], stats.edgecontractcaseatt[SEGMENTSEGMENTEDGE]);
    fprintf(o, "        segment-fixed        %d / %d\n", stats.edgecontractcasesuc[SEGMENTFIXEDEDGE], stats.edgecontractcaseatt[SEGMENTFIXEDEDGE]);
    fprintf(o, "        fixed-fixed          %d / %d\n", stats.edgecontractcasesuc[FIXEDFIXEDEDGE], stats.edgecontractcaseatt[FIXEDFIXEDEDGE]);
    fprintf(o, "    Edge removals:           %d / %d\n", stats.edgeremovals, stats.edgeremovalattempts);
    fprintf(o, "    Boundary edge removals:  %d / %d\n", stats.boundaryedgeremovals, stats.boundaryedgeremovalattempts);
    
    /* find array bounds */
    maxa = maxs = 0;
    for (i=0; i<MAXRINGTETS; i++)
    {
        if (stats.ringsizeattempts[i] != 0) maxa = i;
        if (stats.ringsizesuccess[i] != 0) maxs = i;
    }
    
    /* print histograms */
    fprintf(o, "    Attempt ring sizes (max %d):\n", maxa);
    for (i=3; i<=maxa; i++)
    {
        fprintf(o, "    [%d]: %d\n", i, stats.ringsizeattempts[i]);
    }
    fprintf(o, "    Success ring sizes (max %d):\n", maxs);
    for (i=3; i<=maxs; i++) 
    {
        fprintf(o, "    [%d]: %d\n", i, stats.ringsizesuccess[i]);
    }
    
    fprintf(o, "    Face removals:           %d / %d\n", stats.faceremovals, stats.faceremovalattempts);
    
    /* find array bounds */
    maxa = maxs = 0;
    for (i=0; i<MAXFACETREESIZE; i++)
    {
        if (stats.facesizeattempts[i] != 0) maxa = i;
        if (stats.facesizesuccess[i] != 0) maxs = i;
    }
    
    /* print histograms */
    fprintf(o, "    Attempt tree sizes (max %d):\n", maxa);
    for (i=1; i<=maxa; i++)
    {
        fprintf(o, "    [%d]: %d\n", i, stats.facesizeattempts[i]);
    }
    fprintf(o, "    Success tree sizes (max %d):\n", maxs);
    for (i=1; i<=maxs; i++)
    {
        fprintf(o, "    [%d]: %d\n", i, stats.facesizesuccess[i]);
    }
    fprintf(o, "     2-2 flips:              %d / %d\n", stats.flip22successes, stats.flip22attempts);
    
    /* insertion stats */
    fprintf(o, "\nVertex insertion stats:\n");
    fprintf(o, "    Body insertions:         %d / %d\n", stats.bodyinsertsuccesses, stats.bodyinsertattempts);
    fprintf(o, "    Facet insertions:        %d / %d\n", stats.facetinsertsuccesses, stats.facetinsertattempts);
    fprintf(o, "    Segment insertions:      %d / %d\n", stats.segmentinsertsuccesses, stats.segmentinsertattempts);
    
    /* find array bounds */
    maxb = maxl = 0;
    for (i=0; i<MAXCAVDEPTH; i++)
    {
        if (stats.biggestcavdepths[i] != 0) maxb = i;
        if (stats.lexmaxcavdepths[i] != 0) maxl = i;
    }
    fprintf(o, "    Biggest cavity depths (max %d):\n", maxb);
    for (i=0; i<=maxb; i++)
    {
        fprintf(o, "    [%d]: %d\n", i, stats.biggestcavdepths[i]);
    }
    fprintf(o, "    Lexmax cavity depths (max %d):\n", maxl);
    for (i=0; i<=maxl; i++)
    {
        fprintf(o, "    [%d]: %d\n", i, stats.lexmaxcavdepths[i]);
    }
    
    /* get the current time for animation stuff */
    if (improvebehave.timeseries)
    {
#ifndef NO_TIMER
        gettimeofday(&now, &tz);
        stats.totalmsec = msecelapsed(stats.starttime, now);
#endif /* not NO_TIMER */
        stats.finishnumtets = counttets(mesh);
    }
    
    /* timing stats */
    fprintf(o, "\nTiming stats:\n");
    fprintf(o, "    Smoothing msec: %d\n", stats.smoothmsec);
    fprintf(o, "    Topological msec: %d\n", stats.topomsec);
    fprintf(o, "    Insertion msec: %d\n", stats.insertmsec);
    fprintf(o, "    Contraction msec: %d\n", stats.contractmsec);
    fprintf(o, "    Total msec:     %d\n", stats.totalmsec);
    fprintf(o, "    maxcavusec:     %d\n", stats.biggestcavityusec);
    fprintf(o, "    fincavusec:     %d\n", stats.finalcavityusec);
    fprintf(o, "    improvecavusec: %d\n", stats.cavityimproveusec);
    
    fprintf(o, "Star/End vertex count:       %d / %d\n", stats.startnumverts, stats.startnumverts + stats.bodyinsertsuccesses + stats.facetinsertsuccesses + stats.segmentinsertsuccesses);
    fprintf(o, "Start/End tet count:         %d / %d\n\n", stats.startnumtets, stats.finishnumtets );
    
    /* quality stats */
    fprintf(o, "Quality stats:\n");
    fprintf(o, "    Mean qualities:\n");
    for (i=0; i<NUMMEANTHRESHOLDS; i++)
    {
        fprintf(o, "    [%d]: %g (%g degrees)\n", meanthresholdangles[i], stats.finishmeanquals[i], sintodeg(stats.finishmeanquals[i]));
    }
    
    /* quality stats */
    fprintf(o, "\n    StartMean qualities:\n");
    for (i=0; i<NUMMEANTHRESHOLDS; i++)
    {
        fprintf(o, "    [%d]: %g (%g degrees)\n", meanthresholdangles[i], stats.startmeanquals[i], sintodeg(stats.startmeanquals[i]));
    }
    fprintf(o, "\n    Startworstqual: %g\n", stats.startworstqual);
    fprintf(o, "    Startminangle: %g\n", stats.startminangle);
    fprintf(o, "    Startmaxangle: %g\n", stats.startmaxangle);
    
    fprintf(o, "    dynchangedvol: %g\n", stats.dynchangedvol);
    
    /* cavity sizes */
/*    fprintf(o, "\n    Maxcavity sizes:\n");
    for (i=0; i<1000; i++)
    {
        fprintf(o, "[%d]: %d ", i, stats.maxcavitysizes[i]);
    }
    fprintf(o, "\n    Finalcavity sizes:\n");
    for (i=0; i<200; i++)
    {
        fprintf(o, "[%d]: %d ", i, stats.finalcavitysizes[i]);
    }*/
    
    sizereportstream(o, mesh);
}

void printstats(tetcomplex *mesh)
{
    printstatsstream(stdout, mesh);
}

void printmeans(starreal means[])
{
    int i;
    for (i=0; i<NUMMEANTHRESHOLDS; i++)
    {
        printf("    [%d]: %g (%g degrees)\n", meanthresholdangles[i], means[i], sintodeg(means[i]));
    }
}

<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineBranchExtractor.h<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkCenterlineBranchExtractor.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:46:43 $
Version:   $Revision: 1.5 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// .NAME vtkvmtkCenterlineBranchExtractor - Split and group centerlines.
// .SECTION Description
// A centerline is split into individual tracts and the tracts are merged together into branches. 
//
// Tracts are formed (in the example of a bifurcation, though this is generalized to a n-furcation), by identifying two points on each centerline (which we termed the reference points). The first is located where the centerline intersects another centerline’s tube (in the vascular tree assumption, each centerline will intersect all the other centerlines’ tube once). The second is located one maximum inscribed sphere upstream. The second reference point may be thought of as the start of the bifurcation region. We can then identify three tracts along each centerline, the first preceding the bifurcation, the second lying in-between the two points and the last following the bifurcation
//
// Note that in the first tract the two centerlines are one in each other’s tube. The same thing holds true for the second tract, since by definition the second tract ends where the centerlines exit the other centerline’s tube. The last tracts are instead outside each other’s tube.
//
// We can therefore group the tracts based on these tube containment relationships: the first group will be composed of the first tracts of the two centerlines, the second of the second tracts of the two centerlines, the ones located at the bifurcation region in-between the reference points, the third of the second tract of the first centerline and the fourth of the second tract of the second centerline. Each group will basically represent a branch, except for the second group, which will be relative to the bifurcation.
//
// This process gives us the "Blanking" label for tracts free of charge. Tracts which lie between the two reference points (within the bifurcation region), are said to be Blanked. This is label will become important during processing steps downstream in the pipeline.

#ifndef __vtkvmtkCenterlineBranchExtractor_h
#define __vtkvmtkCenterlineBranchExtractor_h

#include "vtkvmtkCenterlineSplittingAndGroupingFilter.h"
//#include "vtkvmtkComputationalGeometryWin32Header.h"
#include "vtkvmtkWin32Header.h"
  
class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineBranchExtractor : public vtkvmtkCenterlineSplittingAndGroupingFilter
{
  public: 
  vtkTypeMacro(vtkvmtkCenterlineBranchExtractor,vtkvmtkCenterlineSplittingAndGroupingFilter);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; 

  static vtkvmtkCenterlineBranchExtractor *New();
  
  protected:
  vtkvmtkCenterlineBranchExtractor();
  ~vtkvmtkCenterlineBranchExtractor();  

  virtual void ComputeCenterlineSplitting(vtkPolyData* input, vtkIdType cellId) VTK_OVERRIDE;
  virtual void GroupTracts(vtkPolyData* input, vtkPolyData* centerlineTracts) VTK_OVERRIDE;

  private:
  vtkvmtkCenterlineBranchExtractor(const vtkvmtkCenterlineBranchExtractor&);  // Not implemented.
  void operator=(const vtkvmtkCenterlineBranchExtractor&);  // Not implemented.
};

#endif


<|start_filename|>vtkVmtk/ComputationalGeometry/vtkvmtkReferenceSystemUtilities.cxx<|end_filename|>
/*=========================================================================

Program:   VMTK
Module:    $RCSfile: vtkvmtkReferenceSystemUtilities.cxx,v $
Language:  C++
Date:      $Date: 2005/07/28 16:11:52 $
Version:   $Revision: 1.1 $

  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "vtkvmtkReferenceSystemUtilities.h"
#include "vtkPolyData.h"
#include "vtkPointData.h"
#include "vtkObjectFactory.h"


vtkStandardNewMacro(vtkvmtkReferenceSystemUtilities);

vtkIdType vtkvmtkReferenceSystemUtilities::GetReferenceSystemPointId(vtkPolyData* referenceSystems, const char* groupIdsArrayName, vtkIdType groupId)
{
  vtkDataArray* groupIdsArray = referenceSystems->GetPointData()->GetArray(groupIdsArrayName);
  int numberOfPoints = referenceSystems->GetNumberOfPoints();

  vtkIdType pointId = -1;
  for (int i=0; i<numberOfPoints; i++)
  {
    vtkIdType current_groupId = static_cast<int>(groupIdsArray->GetComponent(i,0));
    if (current_groupId == groupId)
    {
      pointId = i;
      break;
    }
  }
  return pointId;
}


<|start_filename|>vtkVmtk/Utilities/Stellar_1.0/src/insertion.c<|end_filename|>
/*****************************************************************************/
/*                                                                           */
/*  Vertex insertion routines                                                */
/*                                                                           */
/*****************************************************************************/

/* check an array of tets to see if it contains the query tet */
bool tetinlist(tag v1,
               tag v2,
               tag v3,
               tag v4,
               tag list[][4],
               int listsize)
{
    int i;
    
    for (i=0; i<listsize; i++)
    {
        if (sametet(v1, v2, v3, v4, list[i][0], list[i][1], list[i][2], list[i][3]))
        {
            return true;
        }
    }
    
    return false;
}

/* check an array of faces to see if it contains the query face */
bool faceinlist(tag v1,
                tag v2,
                tag v3,
                tag list[][3],
                int listsize)
{
    int i;
    
    for (i=0; i<listsize; i++)
    {
        if (sameface(v1, v2, v3, list[i][0], list[i][1], list[i][2]))
        {
            return true;
        }
    }
    
    return false;
}

/* removed the specified face from a face list */
void deletelistface(tag v1,
                    tag v2,
                    tag v3,
                    tag list[][3],
                    int *listsize)
{
    int i,j;
    bool found = false;
    
    /* find face in the list */
    for (i=0; i<*listsize; i++)
    {
        if (sameface(v1, v2, v3, list[i][0], list[i][1], list[i][2]))
        {
            found = true;
            break;
        }
    }
    
    assert(found);
    
    /* slide all the rest of the faces back */
    for (j=i; i<*listsize-1; i++)
    {
        list[i][0] = list[i+1][0];
        list[i][1] = list[i+1][1];
        list[i][2] = list[i+1][2];
    }
    
    /* decrement the list size */
    (*listsize)--;
}

/* removed the specified tet from a tet list */
void deletelisttet(tag v1,
                   tag v2,
                   tag v3,
                   tag v4,
                   tag list[][4],
                   int *listsize)
{
    int i,j;
    bool found = false;
    
    /* find face in the list */
    for (i=0; i<*listsize; i++)
    {
        if (sametet(v1, v2, v3, v4, list[i][0], list[i][1], list[i][2], list[i][3]))
        {
            found = true;
            break;
        }
    }
    
    assert(found);
    
    /* slide all the rest of the faces back */
    for (j=i; i<*listsize-1; i++)
    {
        list[i][0] = list[i+1][0];
        list[i][1] = list[i+1][1];
        list[i][2] = list[i+1][2];
        list[i][3] = list[i+1][3];
    }
    
    /* decrement the list size */
    (*listsize)--;
}

/* add the specified tet to a list */
void addlisttet(tag v1,
                tag v2,
                tag v3,
                tag v4,
                tag list[][4],
                int *listsize)
{
    /* check that we're not adding a duplicate */
    assert(tetinlist(v1, v2, v3, v4, list, *listsize) == false);
    
    list[*listsize][0] = v1;
    list[*listsize][1] = v2;
    list[*listsize][2] = v3;
    list[*listsize][3] = v4;
    (*listsize)++;
}

/* add the specified face to a list */
void addlistface(tag v1,
                 tag v2,
                 tag v3,
                 tag list[][3],
                 int *listsize)
{
    list[*listsize][0] = v1;
    list[*listsize][1] = v2;
    list[*listsize][2] = v3;
    (*listsize)++;
}

#define NOCAVITYTET -1
#define NOCAVITYFACE -1

struct cavityface
{
    tag verts[3];
    starreal qual;
    int child;
    bool inH;
};

struct cavityedge
{
    starreal qual;
    int parent;
    int child;
    int childnum;
};

#define EDGELABEL 0
#define TETLABEL 1

struct cavityedgeortet
{
    starreal qual;
    int label;
    int parent;
    int child;
    int childnum;
};

struct cavitytet
{
    tag verts[4];
    starreal qual;
    int numoutfaces;
    int depth;
    struct cavityface outfaces[MAXOUTFACES];
    int parents[3];
    int label;
};

void printcavitytet(struct cavitytet *tet)
{
    int i;
    
    printf("    Cavity tet with verts (%d %d %d %d)\n", (int) tet->verts[0], (int) tet->verts[1], (int) tet->verts[2], (int) tet->verts[3]);
    printf("    Label: %d\n", tet->label);
    printf("    Quality: %g\n", pq(tet->qual));
    printf("    Depth: %d\n", tet->depth);
    printf("    Parents are %d, %d, and %d\n", tet->parents[0], tet->parents[1], tet->parents[2]);
    printf("    Has %d outgoing faces:\n", tet->numoutfaces);
    for(i=0; i<tet->numoutfaces; i++)
    {
        printf("        Face %d (%d %d %d) has quality %g and child %d\n", 
                        i, (int) tet->outfaces[i].verts[0], (int) tet->outfaces[i].verts[1], (int) tet->outfaces[i].verts[2],
                        pq(tet->outfaces[i].qual), tet->outfaces[i].child);
    }
}

void printcavitydag(struct tetcomplex *mesh,
                    struct cavitytet cavity[],
                    int cavitysize)
{
    int i;
    
    for (i=0; i<cavitysize; i++)
    {
        printf("Tet %d/%d:\n", i, cavitysize-1);
        printcavitytet(&cavity[i]);
    }
    
    /*printf("{");
    for (i=0; i<cavitysize; i++)
    {
        printtetverts(mesh, cavity[i].verts);
        printf(";\n");
    }
    printf("};\n");*/
}

/* check an array of tets to see if it contains the query tet.
   if so, return its location. if not, return NOCAVITYTET */
int cavitytetinlist(tag v1,
                    tag v2,
                    tag v3,
                    tag v4,
                    struct cavitytet list[],
                    int listsize)
{
    int i;
    
    for (i=0; i<listsize; i++)
    {
        if (sametet(v1, v2, v3, v4,
                    list[i].verts[0],
                    list[i].verts[1],
                    list[i].verts[2],
                    list[i].verts[3]))
        {
            return i;
        }
    }
    
    return NOCAVITYTET;
}

/* check a tet to see if it contains the query face.
   if so, return its location. if not, return NOCAVITYFACE */
int cavityfaceintet(tag v1,
                    tag v2,
                    tag v3,
                    struct cavitytet *tet)
{
    int i;
    int numfaces = tet->numoutfaces;
    
    for (i=0; i<numfaces; i++)
    {
        if (sameface(v1, v2, v3,
                     tet->outfaces[i].verts[0],
                     tet->outfaces[i].verts[1],
                     tet->outfaces[i].verts[2]))
        {
            return i;
        }
    }
    
    return NOCAVITYFACE;
}

/* add a tet to the cavity */
void addcavitytet(struct cavitytet *tet,
                  struct cavitytet list[],
                  int *listsize)
{
    /* copy the tet into the list */
    memcpy(&list[*listsize], tet, sizeof(struct cavitytet));
    /* increment list size */
    (*listsize)++;
}

/* return the number of parents a tet has */
int numparents(struct cavitytet *tet)
{
    int numparents = 0;
    if (tet->parents[0] != NOCAVITYTET) numparents++;
    if (tet->parents[1] != NOCAVITYTET) numparents++;
    if (tet->parents[2] != NOCAVITYTET) numparents++;
    return numparents;
}

/* add an outgoing face to a cavity tet */
void addcavitytetface(struct cavitytet *tet,
                      struct cavityface *face)
{
    int whichface, parentcount = 0;
    
    /* check if this face already exists (i.e., we're updating it) */
    whichface = cavityfaceintet(face->verts[0], 
                                face->verts[1], 
                                face->verts[2], 
                                tet);
    
    /* we can't add a new face if there are already 3 */
    if (whichface == NOCAVITYFACE)
    {
        /* make sure that the sum of the parents and outbound faces is 4 */
        parentcount = numparents(tet);
        /* allow more than 3 outfaces for parentless tets */
        if (parentcount != 0)
        {
            if (parentcount + tet->numoutfaces > 3)
            {
                printf("adding face (%d %d %d) with child %d would cause in+out to exceed 4.\n", (int) face->verts[0], (int) face->verts[1], (int) face->verts[2], face->child);
                printcavitytet(tet);
            }
            assert(parentcount + tet->numoutfaces < 4);
        }
        whichface = tet->numoutfaces;
        (tet->numoutfaces)++;
    }
    
    assert(tet->numoutfaces <= MAXOUTFACES);
    
    /* copy in the face */
    memcpy(&tet->outfaces[whichface], face, sizeof(struct cavityface));
}

/* return the number of faces of the tet t that are positively
   oriented with respect to the vertex v */
int numpositivefaces(struct tetcomplex * mesh,
                     tag t[4],
                     starreal *v)
{
    starreal *c[4];
    int numpositive = 0;
    
    /* fetch coordinates of tet vertices */
    c[0] = ((struct vertex *) tetcomplextag2vertex(mesh, t[0]))->coord;
    c[1] = ((struct vertex *) tetcomplextag2vertex(mesh, t[1]))->coord;
    c[2] = ((struct vertex *) tetcomplextag2vertex(mesh, t[2]))->coord;
    c[3] = ((struct vertex *) tetcomplextag2vertex(mesh, t[3]))->coord;
    
    /* test each faces orientation */
    /* faces are:
       (1, 2, 3), (0, 3, 2), (0, 1, 3), (0, 2, 1) */
    if (orient3d(&behave, v, c[1], c[2], c[3]) > MINFACING) numpositive++;
    if (orient3d(&behave, v, c[0], c[3], c[2]) > MINFACING) numpositive++;
    if (orient3d(&behave, v, c[0], c[1], c[3]) > MINFACING) numpositive++;
    if (orient3d(&behave, v, c[0], c[2], c[1]) > MINFACING) numpositive++;
    
    /* we can have at most 3 positively oriented faces */
    assert(numpositive < 4);
    
    if (improvebehave.verbosity > 5)
    {
        printf("Tet checked has %d faces oriented toward v\n", numpositive);
    }
    
    return numpositive;
}

/* check the DAG to make sure it's constructed correctly */
bool cavitydagcheck(struct tetcomplex *mesh,
                    struct cavitytet cavity[],
                    int cavitysize)
{
    int i,j,k, parentcount, child;
    tag othervert;
    
    for (i=0; i<cavitysize; i++)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("checking out tet %d\n", i);
            printcavitytet(&cavity[i]);
        }
        
        assert(tetexists(mesh, 
                         cavity[i].verts[0],
                         cavity[i].verts[1],
                         cavity[i].verts[2],
                         cavity[i].verts[3]));
        
        parentcount = numparents(&cavity[i]);
        
        /* let "no parent" tets get by */
        if (parentcount == 0)
        {
            continue;
        } 
        
        /* check that numparents + numoutfaces = 4 
           (i.e., all faces of tet are accounted for) */
        assert(parentcount > 0);
        assert(parentcount + cavity[i].numoutfaces == 4);
        
        for (j=0; j<cavity[i].numoutfaces; j++)
        {
            /* check that the face has a non-negative quality */
            assert(cavity[i].outfaces[j].qual >= 0);
            
            /* find the vertex not in this face */
            othervert = GHOSTVERTEX;
            for (k=0; k<4; k++)
            {
                if ((cavity[i].verts[k] != cavity[i].outfaces[j].verts[0]) &&
                    (cavity[i].verts[k] != cavity[i].outfaces[j].verts[1]) &&
                    (cavity[i].verts[k] != cavity[i].outfaces[j].verts[2]))
                {
                    othervert = cavity[i].verts[k];
                }
            }
            assert(othervert != GHOSTVERTEX);
            
            /* check that the face is oriented outward */
            assert(tetexists(mesh,
                             othervert, 
                             cavity[i].outfaces[j].verts[2],
                             cavity[i].outfaces[j].verts[1],
                             cavity[i].outfaces[j].verts[0]));
            
            /* check that each child of this tet has this tet for a parent */
            child = cavity[i].outfaces[j].child;
            if (child != NOCAVITYTET)
            {
                assert(cavity[child].parents[0] == i || 
                       cavity[child].parents[1] == i ||
                       cavity[child].parents[2] == i);
            }
        }
    }
    
    return true;
}

/* given a vertex, it's position, an initial cavitiy of tets and 
   a set of outward-oriented faces of that cavity, build a DAG
   representing the largest star-shaped cavity from the point of
   view of the inserted vertex */
void buildcavitydag(struct tetcomplex *mesh,
                    tag vtag,
                    tag initialC[][4],
                    int initialCsize,
                    tag initialF[][3],
                    int initialFsize,
                    struct cavitytet outcavity[],
                    int *cavitysize,
                    bool allowvertexdeletion)
{
    static tag F[MAXCAVITYFACES][3]; /* candidate face list */
    static tag W[MAXCAVITYFACES][3]; /* wall face list */
    static tag C[MAXCAVITYTETS][4];  /* cavity tet list */
    static tag B[MAXCAVITYTETS][4];  /* blocking tet list */
    int Fsize=0, Wsize=0, Csize=0, Bsize=0;
    tag t[4];                 /* current tet */
    tag f[3];                 /* current face */
    tag outin[2];
    tag outin2[2];
    starreal *c[4];
    starreal *v;
    bool foundface;
    int Wcount = 0;
    bool facing = true;
    int i,j;
    tag otherfaces[3][3] = {{2,1,0},{3,2,0},{0,1,3}};
    int deepest = 0;
    int numnonwall = 0;
    tag nonwall[3];
    int ii;
    
    int depthlimit = improvebehave.cavdepthlimit;
    
    /* output cavity stuff */
    struct cavitytet cavtet;
    struct cavityface cavface;
    struct cavityface cavface2;
    int tetindex, parentindex;
    
    *cavitysize = 0;
    
    /* fetch position of new vertex */
    v = ((struct vertex *) tetcomplextag2vertex(mesh, vtag))->coord;
    
    /* initialize cavity tet list */
    for (i=0; i<initialCsize; i++)
    {
        addlisttet(initialC[i][0], initialC[i][1], initialC[i][2], initialC[i][3], C, &Csize);
        
        /* this tet is sure to be in the final cavity, add it */
        cavtet.verts[0] = initialC[i][0];
        cavtet.verts[1] = initialC[i][1];
        cavtet.verts[2] = initialC[i][2];
        cavtet.verts[3] = initialC[i][3];
        /* fake the qual because these tets were already split and made worse */
        cavtet.qual = 1.0;
        cavtet.depth = 0;
        cavtet.parents[0] = NOCAVITYTET;
        cavtet.parents[1] = NOCAVITYTET;
        cavtet.parents[2] = NOCAVITYTET;
        cavtet.numoutfaces = 0;
        
        addcavitytet(&cavtet, outcavity, cavitysize);
    }
    
    /* initialize candidate face list */
    for (i=0; i<initialFsize; i++)
    {
        addlistface(initialF[i][0], initialF[i][1], initialF[i][2], F, &Fsize);
    }
    
    /* now, as long as we have candidate faces */
    while (Fsize > 0)
    {
        assert(*cavitysize <= MAXCAVITYTETS);
        assert(Fsize <= MAXCAVITYFACES);
        assert(Wsize <= MAXCAVITYFACES);
        assert(Csize <= MAXCAVITYTETS);
        assert(Bsize <= MAXCAVITYTETS);
        
        if (improvebehave.verbosity > 5)
        {
            printf("going through face list, size is %d\n", Fsize);
            printf("Csize = %d, Bsize = %d, Wsize = %d\n", Csize, Bsize, Wsize);
        }
        
        /* pull a face out of F */
        f[0] = F[Fsize-1][0];
        f[1] = F[Fsize-1][1];
        f[2] = F[Fsize-1][2];
        Fsize--;
        
        if (improvebehave.verbosity > 5)
        {
            printf("just pulled face (%d %d %d) out of F\n", (int) f[0], (int) f[1], (int) f[2]);
            printf("here's F (size = %d):\n", Fsize);
            for (ii=0; ii<Fsize; ii++)
            {
                printf("%d: %d %d %d\n", ii, (int) F[ii][0], (int) F[ii][1], (int) F[ii][2]);
            }
        }
        
        /* get t, the tet on the other side of this face */
        foundface = tetcomplexadjacencies(mesh, f[0], f[1], f[2], outin);
        if (foundface == 0)
        {
            printf("couldn't find face (%d %d %d)", (int) f[0], (int) f[1], (int) f[2]);
        }
        assert(foundface);
        /* make sure the parent tet for this face is there */
        assert(outin[1] != GHOSTVERTEX);
        
        /* the inward facing tet should already be in the output cavity.
           find it, and add this face as an outgoing face */
        tetindex = cavitytetinlist(outin[1], f[2], f[1], f[0], outcavity, *cavitysize);
        assert(tetindex != NOCAVITYTET);
        
        /* compute the quality of the cavity tet with this face */
        cavface.verts[0] = f[0];
        cavface.verts[1] = f[1];
        cavface.verts[2] = f[2];
        cavface.qual = tetquality(mesh, vtag, f[2], f[1], f[0], improvebehave.qualmeasure);
        assert(cavface.qual > 0);
        
        /* check to make sure it's not a ghost vertex */
        if (outin[0] == GHOSTVERTEX)
        {
            /* note that this face has no child, and assign it to its parent tet */
            cavface.child = NOCAVITYTET;
            addcavitytetface(&outcavity[tetindex], &cavface);
            
            /* add this face to the wall list */
            addlistface(f[0], f[1], f[2], W, &Wsize);
            continue;
        }
        
        t[0] = outin[0];
        t[1] = f[0];
        t[2] = f[1];
        t[3] = f[2];
        
        if (improvebehave.verbosity > 5)
        {
            printf("investigating tet (%d %d %d %d)\n", (int) t[0], (int) t[1], (int) t[2], (int) t[3]);
        }
        
        /* fetch positions of vertices */
        c[0] = ((struct vertex *) tetcomplextag2vertex(mesh, t[0]))->coord;
        c[1] = ((struct vertex *) tetcomplextag2vertex(mesh, t[1]))->coord;
        c[2] = ((struct vertex *) tetcomplextag2vertex(mesh, t[2]))->coord;
        c[3] = ((struct vertex *) tetcomplextag2vertex(mesh, t[3]))->coord;
        
        /* is t a cavity tet? */
        if (tetinlist(t[0], t[1], t[2], t[3], C, Csize))
        {
            if (improvebehave.verbosity > 4)
            {
                printf("it's already a cavity tet. can this happen?\n");
            }
            starexit(1);
            
            /* we need to add this face to the parent tet, indicating 
               that it has no child because the tet on the other side
               doesn't depend in it's removal to exist */
            cavface.child = NOCAVITYTET;
            addcavitytetface(&outcavity[tetindex], &cavface);
            
            /* yes, do nothing */
            continue;
        }
        
        /* is t a blocking tet? */
        if (tetinlist(t[0], t[1], t[2], t[3], B, Bsize))
        {
            if (improvebehave.verbosity > 5)
            {
                printf("it's a blocking tet.\n");
            }
            
            /* if there is one other wall face of this tet, and the other two faces
               are visible from v, we can add this tet to the cavity. */
            Wcount = 1;
            facing = true;
            
            for (i=0; i<3; i++)
            {
                /* is this face already marked as a wall ? */
                if (faceinlist(t[otherfaces[i][0]], t[otherfaces[i][1]], t[otherfaces[i][2]], W, Wsize))
                {
                    Wcount++;
                }
                else
                /* it's not a wall... is it oriented toward v? */
                {
                    if (orient3d(&behave, v, c[otherfaces[i][0]], c[otherfaces[i][1]], c[otherfaces[i][2]]) <= MINFACING)
                    {
                        facing = false;
                    }
                }
            }
            
            if (improvebehave.verbosity > 5)
            {
                printf("*** facing = %d, wcount = %d\n", facing, Wcount);
            }
            
            /* only allow tets with three parents if we are allowing vertex deletion */
            if ((Wcount == 2 || (Wcount == 3 && allowvertexdeletion)) && facing)
            {
                if (Wcount == 2)
                {
                    if (improvebehave.verbosity > 5)
                    {
                        printf("found a 2-wall face tet to add!\n");
                    }
                }
                else
                {
                    if (improvebehave.verbosity > 5)
                    {
                        printf("found a 3-wall face tet to add!\n");
                    }
                }
                
                /* this tet can be added to the cavity */
                
                /* remove it from B */
                deletelisttet(t[0], t[1], t[2], t[3], B, &Bsize);
                /* add it to C */
                assert(tetexists(mesh, t[0], t[1], t[2], t[3]));
                addlisttet(t[0], t[1], t[2], t[3], C, &Csize);
                
                /* add this tet to the output cavity */
                cavtet.verts[0] = t[0];
                cavtet.verts[1] = t[1];
                cavtet.verts[2] = t[2];
                cavtet.verts[3] = t[3];
                /* compute it's original quality */
                cavtet.qual = tetquality(mesh, t[0], t[1], t[2], t[3], improvebehave.qualmeasure);
                assert(cavtet.qual > 0);
                /* we know one parent must be the one we found above */
                cavtet.parents[0] = tetindex;
                /* the depth is one more than the parent depth */
                cavtet.depth = outcavity[tetindex].depth + 1;
                /* if this is a new deepest, remember it */
                if (cavtet.depth > deepest) deepest = cavtet.depth;
                addcavitytet(&cavtet, outcavity, cavitysize);
                
                /* add this face to the parent tet with the correct child */
                cavface.child = *cavitysize - 1;
                addcavitytetface(&outcavity[tetindex], &cavface);
                
                /* remove any faces that were in W, add others to F. Handle output
                   tet faces that need to be added */
                
                numnonwall = 0;
                /* first, handle all wall face so we can set the correct depth */
                for (i=0; i<3; i++)
                {
                    /* is this already a wall face? */
                    if (faceinlist(t[otherfaces[i][0]], t[otherfaces[i][1]], t[otherfaces[i][2]], W, Wsize))
                    {
                        deletelistface(t[otherfaces[i][0]], t[otherfaces[i][1]], t[otherfaces[i][2]], W, &Wsize);
                        
                        /* because this face was previously a wall face,
                           it has some cavity tet that it belongs to. find
                           this tet in the output cavity and set it's child face */
                        
                        foundface = tetcomplexadjacencies(mesh,   
                                                          t[otherfaces[i][0]], 
                                                          t[otherfaces[i][1]], 
                                                          t[otherfaces[i][2]], 
                                                          outin2);
                        assert(foundface);
                        assert(outin2[1] != GHOSTVERTEX);
                        
                        parentindex = cavitytetinlist(outin2[1], 
                                                      t[otherfaces[i][2]], 
                                                      t[otherfaces[i][1]], 
                                                      t[otherfaces[i][0]], 
                                                      outcavity, *cavitysize);
                        assert(parentindex != NOCAVITYTET);
                    
                        /* add this face to the parent tet's outgoing faces */
                        cavface.verts[0] = t[otherfaces[i][0]];
                        cavface.verts[1] = t[otherfaces[i][1]];
                        cavface.verts[2] = t[otherfaces[i][2]];
                        cavface.qual = tetquality(mesh, vtag, 
                                                  t[otherfaces[i][2]], 
                                                  t[otherfaces[i][1]], 
                                                  t[otherfaces[i][0]], 
                                                  improvebehave.qualmeasure);
                        assert(cavface.qual > 0);
                        cavface.child = *cavitysize - 1;
                        /* make sure that this face is already in this tet */
                        assert(cavityfaceintet(cavface.verts[0], 
                                               cavface.verts[1], 
                                               cavface.verts[2], 
                                               &outcavity[parentindex]) != NOCAVITYFACE);
                        addcavitytetface(&outcavity[parentindex], &cavface);
                        
                        /* assign the parent tet as the second parent of the new cavity tet */
                        if (outcavity[*cavitysize -1].parents[1] == NOCAVITYTET)
                        {
                            outcavity[*cavitysize - 1].parents[1] = parentindex;
                        }
                        else
                        {
                            assert(outcavity[*cavitysize -1].parents[2] == NOCAVITYTET);
                            outcavity[*cavitysize - 1].parents[2] = parentindex;
                        }
                        
                        /* if this parent has a lesser depth value, update new tet's depth to be the lesser */
                        if (outcavity[parentindex].depth < outcavity[*cavitysize - 1].depth)
                        {
                            if (improvebehave.verbosity > 5)
                            {
                                printf("changing depth from %d to %d, this parent is shallower\n", outcavity[*cavitysize - 1].depth, outcavity[parentindex].depth);
                            }
                            outcavity[*cavitysize - 1].depth = outcavity[parentindex].depth;
                        }
                    }
                    else
                    {
                        /* record this non-wall face for potential addition to F later */
                        nonwall[numnonwall] = i;
                        numnonwall++;
                    }
                }
                
                for (i=0; i<numnonwall; i++)
                {
                    j = nonwall[i];
                    
                    /* this is a newly-uncovered face. there could be more tets behind it, so
                       we should add it to F, if the current tet's depth isn't more than the max */
                    if (outcavity[*cavitysize -1].depth < depthlimit)
                    {
                        if (improvebehave.verbosity > 5)
                        {
                            printf("adding new face uncovered in 2-parent tet to F (%d %d %d)\n", (int) t[otherfaces[j][2]], (int) t[otherfaces[j][1]], (int) t[otherfaces[j][0]]);
                        }
                        addlistface(t[otherfaces[j][2]], t[otherfaces[j][1]], t[otherfaces[j][0]], F, &Fsize);
                    }
                    /* we should artificially make this a wall face so the cavity doesn't get deeper */
                    else
                    {
                        if (improvebehave.verbosity > 5)
                        {
                            printf("adding new face uncovered in 2-parent tet to W because of depth limit (%d %d %d)\n", (int) t[otherfaces[j][2]], (int) t[otherfaces[j][1]], (int) t[otherfaces[j][0]]);
                        }
                        
                        /* construct output face */
                        cavface2.verts[0] = t[otherfaces[j][2]];
                        cavface2.verts[1] = t[otherfaces[j][1]];
                        cavface2.verts[2] = t[otherfaces[j][0]];
                        cavface2.qual = tetquality(mesh, vtag, cavface2.verts[2], cavface2.verts[1], cavface2.verts[0], improvebehave.qualmeasure);
                        cavface2.child = NOCAVITYTET;
                        assert(cavface2.qual > 0);
                        
                        /* add it to parent tet */
                        addcavitytetface(&outcavity[*cavitysize -1], &cavface2);
                        
                        addlistface(t[otherfaces[j][2]], t[otherfaces[j][1]], t[otherfaces[j][0]], W, &Wsize);
                    }
                }
                
                if (improvebehave.verbosity > 5)
                {
                    printf("just added this 2-wall-face cavity tet (tet %d):\n", *cavitysize - 1);
                    printcavitytet(&outcavity[*cavitysize - 1]);
                }
                assert(outcavity[*cavitysize - 1].parents[0] != NOCAVITYTET);
                assert(outcavity[*cavitysize - 1].parents[1] != NOCAVITYTET);
            }
            else
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("found a blocking tet that didn't work out! facing = %d, wcount = %d\n", facing, Wcount);
                }
                
                /* note that this face has no child, and assign it to its parent tet */
                cavface.child = NOCAVITYTET;
                addcavitytetface(&outcavity[tetindex], &cavface);
                
                /* add f to W, it borders a blocking tet */
                addlistface(f[0], f[1], f[2], W, &Wsize);
            }
            continue;
        }
        
        if (improvebehave.verbosity > 5)
        {
                printf("it's not in B or C.\n");
        }
        
        /* t is neither a blocking tet nor a cavity tet */
        /* check to see if the three other faces of the tet are facing v */
        if ((orient3d(&behave, v, c[2], c[1], c[0]) > MINFACING) &&
            (orient3d(&behave, v, c[3], c[2], c[0]) > MINFACING) &&
            (orient3d(&behave, v, c[0], c[1], c[3]) > MINFACING))
        {
            if (improvebehave.verbosity > 5)
            {
                printf("Adding tet to cavity\n");
            }
            
            /* yes! we can add this tet to the cavity */
            assert(tetexists(mesh, t[0], t[1], t[2], t[3]));
            /* make sure this tet has more than one face oriented toward the new vertex */
            assert(numpositivefaces(mesh, t, v) > 1);
            
            addlisttet(t[0], t[1], t[2], t[3], C, &Csize);
            
            /* add this tet to the output cavity */
            cavtet.verts[0] = t[0];
            cavtet.verts[1] = t[1];
            cavtet.verts[2] = t[2];
            cavtet.verts[3] = t[3];
            /* compute it's original quality */
            cavtet.qual = tetquality(mesh, t[0], t[1], t[2], t[3], improvebehave.qualmeasure);
            assert(cavtet.qual > 0);
            /* it's parent must be the parent above */
            cavtet.parents[0] = tetindex;
            /* depth is one deeper than parent */
            cavtet.depth = outcavity[tetindex].depth + 1;
            /* if this is a new deepest, note it */
            if (cavtet.depth > deepest) deepest = cavtet.depth;
            
            addcavitytet(&cavtet, outcavity, cavitysize);
            
            /* note the current face's child in the parent tet */
            cavface.child = *cavitysize - 1;
            addcavitytetface(&outcavity[tetindex], &cavface);
            
            /* add t's three (outward oriented) faces to F, if the current tet isn't too deep */
            if (cavtet.depth < depthlimit)
            {
                addlistface(t[0], t[1], t[2], F, &Fsize);
                addlistface(t[0], t[2], t[3], F, &Fsize);
                addlistface(t[0], t[3], t[1], F, &Fsize);
            }
            else
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("not adding faces to F because max depth reached...\n");
                }
                
                /* construct output face */
                cavface2.child = NOCAVITYTET;
                
                cavface2.verts[0] = t[0];
                cavface2.verts[1] = t[1];
                cavface2.verts[2] = t[2];
                cavface2.qual = tetquality(mesh, vtag, t[2], t[1], t[0], improvebehave.qualmeasure);
                assert(cavface2.qual > 0);
                /* add it to parent tet */
                addcavitytetface(&outcavity[*cavitysize -1], &cavface2);
                
                cavface2.verts[0] = t[0];
                cavface2.verts[1] = t[2];
                cavface2.verts[2] = t[3];
                cavface2.qual = tetquality(mesh, vtag, t[3], t[2], t[0], improvebehave.qualmeasure);
                assert(cavface2.qual > 0);
                /* add it to parent tet */
                addcavitytetface(&outcavity[*cavitysize -1], &cavface2);
                
                cavface2.verts[0] = t[0];
                cavface2.verts[1] = t[3];
                cavface2.verts[2] = t[1];
                cavface2.qual = tetquality(mesh, vtag, t[1], t[3], t[0], improvebehave.qualmeasure);
                assert(cavface2.qual > 0);
                /* add it to parent tet */
                addcavitytetface(&outcavity[*cavitysize -1], &cavface2);
                
                addlistface(t[0], t[1], t[2], W, &Wsize);
                addlistface(t[0], t[2], t[3], W, &Wsize);
                addlistface(t[0], t[3], t[1], W, &Wsize);
            }
        }
        else
        {
            /* this is a blocking tet, add it to B */
            addlisttet(t[0], t[1], t[2], t[3], B, &Bsize);
            
            /* note the current face in the parent tet */
            cavface.child = NOCAVITYTET;
            addcavitytetface(&outcavity[tetindex], &cavface);
            
            /* add the current face to the wall face list */
            addlistface(f[0], f[1], f[2], W, &Wsize);
        }
    }
    
    /* record the maximum depth */
    stats.biggestcavdepths[deepest]++;
    
    if (improvebehave.verbosity > 5)
    {
        printf("here is the cavity:\n");
        printtets(mesh, C, Csize);
        printf("here is W:\n");
        printfaces(mesh, W, Wsize);
    }
}

/* debug routine to print out edge list */
void printedgelist(struct cavityedge edges[],
                   int numedges)
{
    int i;
    for (i=0; i<numedges; i++)
    {
        printf("Edge %d/%d:\n", i, numedges-1);
        printf("    Qual: %g\n", pq(edges[i].qual));
        printf("    Parent: %d\n", edges[i].parent);
        printf("    Child: %d\n", edges[i].child);
        printf("    Childnum: %d\n", edges[i].childnum);
    }
}

/* debug routine to print out combined tet/edge list */
void printedgeortetlist(struct cavityedgeortet edges[],
                        int numedges)
{
    int i;
    for (i=0; i<numedges; i++)
    {
        printf("Edge %d/%d:\n", i, numedges-1);
        printf("    Label: %d\n", edges[i].label);
        printf("    Qual: %g\n", pq(edges[i].qual));
        printf("    Parent: %d\n", edges[i].parent);
        printf("    Child: %d\n", edges[i].child);
        printf("    Childnum: %d\n", edges[i].childnum);
    }
}

/* compare two edges, to be used for standard qsort call */
int compareedges(const void * a, const void * b)
{
    if ( ((struct cavityedge *)a)->qual > ((struct cavityedge *)b)->qual) return 1;
    if ( ((struct cavityedge *)a)->qual < ((struct cavityedge *)b)->qual) return -1;
    return 0;
}

/* compare two elements in a hybrid edge/tet list, for qsort */
int compareedgeortets(const void * a, const void * b)
{
    if ( ((struct cavityedgeortet *)a)->qual > ((struct cavityedgeortet *)b)->qual) return 1;
    if ( ((struct cavityedgeortet *)a)->qual < ((struct cavityedgeortet *)b)->qual) return -1;
    return 0;
}

/* function to sort an array of edges */
void sortedges(struct cavityedge array[],
               int arraylength)
{
    qsort(array, (size_t) arraylength, sizeof(struct cavityedge), compareedges);
}

/* function to sort an hybrid array of edges/tets */
void sortedgeortets(struct cavityedgeortet array[],
               int arraylength)
{
    qsort(array, (size_t) arraylength, sizeof(struct cavityedgeortet), compareedgeortets);
}

#define CAVLABEL 0
#define ANTICAVLABEL 1
#define NOLABEL 2

/* table of factors by which to augment deeper tets 
   TODO automatically select weights somehow */
#define DEPTHTABLESIZE 10
starreal depthtable[DEPTHTABLESIZE] = {1.0, 
                                       1.6,
                                       2.3,
                                       2.9,
                                       3.3,
                                       3.3,
                                       3.3,
                                       3.3,
                                       3.3,
                                       3.3};

/* recursively label parents and children as cavity tets */
void cavitylabel(struct cavitytet cavity[],
                 int cavitysize,
                 int tetid)
{
    int i;
    
    /* this tet shouldn't yet be labeled */
    assert(cavity[tetid].label == NOLABEL);
    
    /* label this tet as in the cavity */
    cavity[tetid].label = CAVLABEL;
    
    if (improvebehave.verbosity > 5)
    {
        printf("  In cavitylabel, just labeled tet %d\n", tetid);
    }
    
    /* go through all parents in the original graph */
    for (i=0; i<3; i++)
    {
        if (cavity[tetid].parents[i] != NOCAVITYTET)
        {
            /* if this parent is unlabeled, label it */
            if (cavity[cavity[tetid].parents[i]].label == NOLABEL)
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("parent %d = %d is unlabeled. calling cavity() on it\n", i, cavity[tetid].parents[i]);
                }
                cavitylabel(cavity, cavitysize, cavity[tetid].parents[i]);
            }
        }
    }
    
    /* go through all children in H */
    for (i=0; i<cavity[tetid].numoutfaces; i++)
    {
        /* check if this edge is in H */
        if (cavity[tetid].outfaces[i].inH == true)
        {
            /* this can't be an edge leading to t... we should never add those */
            assert(cavity[tetid].outfaces[i].child != NOCAVITYTET);
            
            if (cavity[cavity[tetid].outfaces[i].child].label == NOLABEL)
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("edge to child %d/%d = %d is in H, and child is unlabeled. calling cavity() on it\n", i, cavity[tetid].numoutfaces-1, cavity[tetid].outfaces[i].child);
                }
                cavitylabel(cavity, cavitysize, cavity[tetid].outfaces[i].child);
            }
        }
    }
}

/* recursively label parents and children as anti-cavity tets */
void anticavitylabel(struct cavitytet cavity[],
                 int cavitysize,
                 int tetid)
{
    int i,j,parent,edgetochild;
    
    /* this tet shouldn't yet be labeled */
    assert(cavity[tetid].label == NOLABEL);
    
    /* label this tet as in the anticavity */
    cavity[tetid].label = ANTICAVLABEL;
    
    if (improvebehave.verbosity > 5)
    {
        printf("  In anticavitylabel, just labeled tet %d\n", tetid);
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("now considering parents in H\n");
    }
    /* go through all parents in H */
    for (i=0; i<3; i++)
    {
        parent = cavity[tetid].parents[i];
        
        if (improvebehave.verbosity > 5)
        {
            printf("considering parent %d = %d\n", i, parent);
        }
        
        if (parent != NOCAVITYTET)
        {
            /* is this parent unlabeled ? */
            if (cavity[cavity[tetid].parents[i]].label != NOLABEL)
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("this parent is already labeled, moving on.\n");
                }
                continue;
            }
            
            /* find the edge from this parent down to the child */
            edgetochild = -1;
            for (j=0; j<cavity[parent].numoutfaces; j++)
            {
                if (cavity[parent].outfaces[j].child == tetid)
                {
                    if (improvebehave.verbosity > 5)
                    {
                        printf("found edge from parent down to child = %d\n", j);
                    }
                    edgetochild = j;
                }
            }
            /* make sure we found the edge */
            assert(edgetochild != -1);
            
            /* is this edge in H? */
            if (cavity[parent].outfaces[edgetochild].inH == true)
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("parent %d = %d is unlabeled, and edge from it is in H. calling anticavity() on it\n", i, cavity[tetid].parents[i]);
                }
                anticavitylabel(cavity, cavitysize, cavity[tetid].parents[i]);
            }
        }
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("now considering children in G\n");
    }
    /* go through all children in original graph G */
    for (i=0; i<cavity[tetid].numoutfaces; i++)
    {
        /* if the child is t, it's the end and is already labeled. move on */
        if (cavity[tetid].outfaces[i].child == NOCAVITYTET)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("child %d is t, moving on\n", i);
            }
            continue;
        }
        
        if (cavity[cavity[tetid].outfaces[i].child].label == NOLABEL)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("edge to child %d/%d = %d is unlabeled. calling anticavity() on it\n", i, cavity[tetid].numoutfaces-1, cavity[tetid].outfaces[i].child);
            }
            anticavitylabel(cavity, cavitysize, cavity[tetid].outfaces[i].child);
        }
    }
}


/* ALGORITHM 3 + CONSIDER DELETED TETS*/
/* given the DAG representing the largest possible cavity,
   find the subcavity that has the lexicographically maximum
   quality, then dig it out and connect the exposed faces to 
   the new vertex, returning the new tets as well as the worst
   quality in this cavity */
void lexmaxcavity3(struct tetcomplex *mesh,
                  tag vtag,
                  struct cavitytet cavity[],
                  int cavitysize,
                  tag outtets[][4],
                  int *numouttets,
                  starreal *worstdeleted,
                  starreal *worstincavity)
{
    int i,j;                                 /* loop counters */
    int parentless;                          /* number of tets without parents */
    bool foundparent = false;                /* did we find face parent? */
    static struct cavityedgeortet edges[MAXCAVITYDAGEDGES]; /* list of all edges in the DAG */
    int numedges=0;
    static int unionfind[MAXCAVITYTETS];            /* union-find array */
    int unionfindsize = cavitysize + 1;      /* size of the union-find array */
    int t = cavitysize;                      /* the virtual node t, at the end of array */
    int parentlabel, childlabel;             /* the groups that contain parent and child of an edge */
    starreal depthfactor;
    starreal qual;
    int deepest = 0;
    int parentcount;
    
    static tag outputfaces[MAXCAVITYFACES][3];
    int numoutputfaces = 0;
    
    /* initialize union-find array */
    for (i=0; i<unionfindsize; i++)
    {
        unionfind[i] = -1;
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("Here's the initial DAG:\n");
        printcavitydag(mesh, cavity, cavitysize);
    }
    
    /* first, we modify the given dag a bit. it may have multiple
       parentless tets that correspond to the initial cavity in the
       DAG-building routine. we'll merge them into one "supertet,"
       s, that represents the single root of the dag.
       
       We'll add one other node to the DAG, t, and add an edge from
       all the previously childless faces of the DAG to t.
       
       The algorithm will then proceed by taking all the edges of this
       new DAG, sorted in ascending order of quality, and add them
       to the DAG iff by adding the edge, we do not connect s to t. */
    
    /* merge all the parentless tets at the start of the DAG into
       one supertet s */
    for (i=1; i<cavitysize; i++)
    {
        parentcount = numparents(&cavity[i]);
        
        /* check if this tet is parentless */
        if (parentcount == 0)
        {
        /* copy the outgoing faces back into the first tet */
            for (j=0; j<cavity[i].numoutfaces; j++)
            {
                /* copy face into the first tet */
                addcavitytetface(&cavity[0], &cavity[i].outfaces[j]);
                
                /* make the child of this face point back to the first tet */
                if (cavity[i].outfaces[j].child != NOCAVITYTET)
                {
                    /* find the parent pointer that points back to cavity tet i */
                    if (cavity[cavity[i].outfaces[j].child].parents[0] == i)
                    {
                        cavity[cavity[i].outfaces[j].child].parents[0] = 0;
                        foundparent = true;
                    }
                    if (cavity[cavity[i].outfaces[j].child].parents[1] == i)
                    {
                        assert(foundparent == false);
                        cavity[cavity[i].outfaces[j].child].parents[1] = 0;
                        foundparent = true;
                    }
                    if (cavity[cavity[i].outfaces[j].child].parents[2] == i)
                    {
                        assert(foundparent == false);
                        cavity[cavity[i].outfaces[j].child].parents[2] = 0;
                        foundparent = true;
                    }
                    assert(foundparent == true);
                    foundparent = false;
                }
            }
            
            /* update the parentless tet whose children we just stole to have
               zero outgoing faces */
            cavity[i].numoutfaces = 0;
        }
        else
        {
            /* we've reached the end of the parentless tets; bail */
            break;
        }
    }
    /* save the number of parentless tets */
    parentless = i;

    
    /* now, proceed through the DAG, recording all edges, and deleting child
       information to remove the edges, producing D' */
    for (i=0; i<cavitysize; i++)
    {
        
        /* initialize this tet's label. set s = cavity, others no label */
        if (i == 0)
        {
            cavity[i].label = CAVLABEL;
        }
        else
        {
            cavity[i].label = NOLABEL;
        }
        
        /* compute how much to exagerrate quality because of depth */
        assert(cavity[i].depth >= 0);
        if (cavity[i].depth < DEPTHTABLESIZE)
        {
            depthfactor = depthtable[cavity[i].depth];
        }
        else
        {
            depthfactor = depthtable[DEPTHTABLESIZE - 1];
        }
        assert(depthfactor >= 1.0);
        
        /* and an edgeortet for this tet, if deleted tets are considered */
        if (improvebehave.cavityconsiderdeleted)
        {
            if (i > parentless)
            {
                edges[numedges].label = TETLABEL;
                edges[numedges].parent = i;
                edges[numedges].child = 0;
                edges[numedges].qual = cavity[i].qual * depthfactor;
                numedges++;
                assert(numedges < MAXCAVITYDAGEDGES);
            }
        }
        
        /* for each outgoing face */
        for (j=0; j<cavity[i].numoutfaces; j++)
        {
            edges[numedges].label = EDGELABEL;
            edges[numedges].parent = i;
            edges[numedges].qual = cavity[i].outfaces[j].qual * depthfactor;
            /* save which outgoing face this child was */
            edges[numedges].childnum = j;
            
            if (cavity[i].outfaces[j].child == NOCAVITYTET)
            {
                /* if it has no child tet, make up a virtual edge to t */
                edges[numedges].child = t;
            }
            else
            {
                /* set edge child to be actual child */
                edges[numedges].child = cavity[i].outfaces[j].child;
            }
            numedges++;
            assert(numedges < MAXCAVITYDAGEDGES);
            
            /* initialize H by setting no edges to be in it */
            cavity[i].outfaces[j].inH = false;
        }
    }
    
    /* now, sort the edges in order of ascending quality */
    sortedgeortets(edges, numedges);
    
    /* go through each edge, adding it to D' iff it doesn't
       connect s to t */
    for (i=0; i<numedges; i++)
    {
        /* is this a tet? */
        if (edges[i].label == TETLABEL)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("considering a deleted tet of qual = %g, label = %d\n", pq(edges[i].qual), cavity[edges[i].parent].label);
            }
            
            /* if this tet is unlabeled */
            if (cavity[edges[i].parent].label == NOLABEL)
            {
                /* label this tet for the cavity */
                if (improvebehave.verbosity > 4)
                {
                    printf("found a deleted tet that we want to grab, qual = %g\n", pq(edges[i].qual));
                }
                cavitylabel(cavity, cavitysize, edges[i].parent);
                continue;
            }
        }
        
        /* check parent's label */
        parentlabel = cavity[edges[i].parent].label;
        /* check child's label */
        if (edges[i].child == t)
        {
            /* this child is labeled automatically as anti-cavity */
            childlabel = ANTICAVLABEL;
        }
        else
        {
            childlabel = cavity[edges[i].child].label;
        }
        
        if (improvebehave.verbosity > 5)
        {
            printf("Considering edge %d/%d:\n", i, numedges-1);
            printf("    label       = %d\n", edges[i].label);
            printf("    qual        = %g\n", pq(edges[i].qual));
            printf("    parent      = %d\n", edges[i].parent);
            printf("    child       = %d\n", edges[i].child);
            printf("    parentlabel = %d\n", parentlabel);
            printf("    childlabel  = %d\n", childlabel);
            printf("    t           = %d\n", t);
        }
        
        
        /* if the parent is in the cavity */
        if (parentlabel == CAVLABEL)
        {
            /* and the child is in the anti-cavity */
            if (childlabel == ANTICAVLABEL)
            {
                /* record output face from parent to child */
                if (improvebehave.verbosity > 5)
                {
                    printf("this edge goes from cavity to anticavity, represents output tet.\n");
                }
                
                outputfaces[numoutputfaces][0] = cavity[edges[i].parent].outfaces[edges[i].childnum].verts[0];
                outputfaces[numoutputfaces][1] = cavity[edges[i].parent].outfaces[edges[i].childnum].verts[1];
                outputfaces[numoutputfaces][2] = cavity[edges[i].parent].outfaces[edges[i].childnum].verts[2];
                numoutputfaces++;
            }
            /* otherwise, if the child isn't labeled */
            else
            {
                if (childlabel == NOLABEL)
                {
                    if (improvebehave.verbosity > 5)
                    {
                        printf("parent is in cavity, child is unlabeled. calling cavity(child)\n");
                    }
                    cavitylabel(cavity, cavitysize, edges[i].child);
                }
            }
        }
        /* parent isn't labeled cavity. */
        else
        {
            /* is the parent wholly unlabeled ? */
            if (parentlabel == NOLABEL)
            {
                /* is the child labeled anti-cavity ? */
                if (childlabel == ANTICAVLABEL)
                {
                    if (improvebehave.verbosity > 5)
                    {
                        printf("parent is unlabeled, child is labeled anticavity. calling anticavity(parent)\n");
                    }
                    anticavitylabel(cavity, cavitysize, edges[i].parent);
                }
                else
                /* neither the parent nor the child is labeled */
                {
                    /* add the edge from parent to child to H */
                    if (improvebehave.verbosity > 5)
                    {
                        printf("parent and child unlabeled. adding edge to H\n");
                    }
                    cavity[edges[i].parent].outfaces[edges[i].childnum].inH = true;
                }
            }
        }
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("Here's the final DAG:\n");
        printcavitydag(mesh, cavity, cavitysize);
    }
    
    /* first sanity check: every tet in the dag should be labeled */
    if (improvebehave.verbosity > 5)
    {
        for (i=0; i<cavitysize; i++)
        {
            printf("tet %d has label %d\n", i, cavity[i].label);
            if (numparents(&cavity[i]) != 0)
            {
                if (cavity[i].label == NOLABEL)
                {
                    printf("uhoh. tet %d has label %d, strange...\n", i, cavity[i].label);
                }
                assert(cavity[i].label != NOLABEL);
            }
        }
        if (improvebehave.verbosity > 5)
        {
            printf("they are all in one or another yay!\n");
            printf("here are the output faces:\n");
            printfaces(mesh, outputfaces, numoutputfaces);
        }
    }
    
    /* delete the non-root parentless tets */
    for (i=1; i<parentless; i++)
    {
        assert(tetexists(mesh, cavity[i].verts[0], 
                               cavity[i].verts[1],
                               cavity[i].verts[2],
                               cavity[i].verts[3]));
        deletetet(mesh, cavity[i].verts[0],
                        cavity[i].verts[1],
                        cavity[i].verts[2],
                        cavity[i].verts[3],
                        true);
    }
    
    /* keep track of what the deepest tet in the final cavity was */
    deepest = 0;
    
    /* delete all tets labeled as cavity */
    *worstdeleted = HUGEFLOAT;
    for (i=0; i<cavitysize; i++)
    {
        if (cavity[i].label == CAVLABEL)
        {
            /* is this the worst quality tet we're deleting? */
            if (cavity[i].qual < *worstdeleted)
            {
                *worstdeleted = cavity[i].qual;
            }
            
            /* is this the deepest tet we've encountered? */
            if (cavity[i].depth > deepest)
            {
                deepest = cavity[i].depth;
            }
            
            assert(tetexists(mesh, cavity[i].verts[0], 
                                   cavity[i].verts[1], 
                                   cavity[i].verts[2], 
                                   cavity[i].verts[3]));
            deletetet(mesh, cavity[i].verts[0],
                           cavity[i].verts[1],
                           cavity[i].verts[2],
                           cavity[i].verts[3],
                           true);
        }
    }
    
    /* record depth of deepest tet */
    stats.lexmaxcavdepths[deepest]++;
    
    /* now build the output cavity using the output faces */
    *numouttets = 0;
    for (i=0; i<numoutputfaces; i++)
    {
        assert(tetexists(mesh, vtag,
                               outputfaces[i][2],
                               outputfaces[i][1],
                               outputfaces[i][0]) == false);
        /* the face is oriented outward, so reverse it to point back */
        if (improvebehave.verbosity > 5)
        {
            printf("about to insert tet (%d %d %d %d)\n", (int) vtag, (int) outputfaces[i][2], (int) outputfaces[i][1], (int) outputfaces[i][0]);
        }
        
        inserttet(mesh, vtag, outputfaces[i][2], outputfaces[i][1], outputfaces[i][0], true);
        qual = tetquality(mesh, vtag, outputfaces[i][2], outputfaces[i][1], outputfaces[i][0], improvebehave.qualmeasure);
        assert(qual > 0);
        if (qual < *worstincavity) *worstincavity = qual;
    
        outtets[*numouttets][0] = vtag;
        outtets[*numouttets][1] = outputfaces[i][2];
        outtets[*numouttets][2] = outputfaces[i][1];
        outtets[*numouttets][3] = outputfaces[i][0];
        (*numouttets)++;
    }
    if (improvebehave.verbosity > 5)
    {
        printf("here are the output cavity tets:\n");
        printtets(mesh, outtets, *numouttets);
    }
}


/* given a vertex, it's position, and an initial cavity of tets
   and a set of outward-oriented faces of that cavity, dig out an
   optimal cavity around the vertex and connect the central vertex
   to all of the cavity faces, and return a list of the new tets */
void optimalcavity(struct tetcomplex *mesh,
                   tag vtag,
                   tag initialC[][4],
                   int initialCsize,
                   tag initialF[][3],
                   int initialFsize,
                   tag outtets[][4],
                   int *numouttets,
                   starreal *worstdeleted,
                   starreal *worstincavity,
                   bool allowvertexdeletion)
{
    int cavitysize;
    static struct cavitytet cavity[MAXCAVITYTETS];
#ifndef NO_TIMER
    struct timeval tv0, tv1;
    struct timezone tz;
#endif /* not NO_TIMER */

    *worstdeleted = HUGEFLOAT;
    *worstincavity = HUGEFLOAT;
    
    /* construct the DAG of the largest possible cavity */
#ifndef NO_TIMER
    gettimeofday(&tv0, &tz);
#endif /* not NO_TIMER */
    buildcavitydag(mesh, vtag, 
                   initialC, initialCsize,
                   initialF, initialFsize,
                   cavity, &cavitysize, allowvertexdeletion);
#ifndef NO_TIMER
    gettimeofday(&tv1, &tz);
    stats.biggestcavityusec += usecelapsed(tv0, tv1);
#endif /* not NO_TIMER */
    
    if (improvebehave.verbosity > 5)
    {
        printf("Largest possible cavity is %d tets\n", cavitysize);
    }
    
    /* keep track of cavity sizes seen */
    stats.maxcavitysizes[cavitysize]++;
    
    if (improvebehave.verbosity > 5)
    {
        printf("here is the DAG of biggest:\n");
        printcavitydag(mesh, cavity, cavitysize);
    }
    
    /* check consistency of DAG */
    /*
    assert(cavitydagcheck(mesh, cavity, cavitysize));
    */
    
    /* build the cavity of maximum lexicographic quality */
#ifndef NO_TIMER
    gettimeofday(&tv0, &tz);
#endif /* not NO_TIMER */
    lexmaxcavity3(mesh, vtag, cavity, cavitysize, outtets, numouttets, worstdeleted, worstincavity);
#ifndef NO_TIMER
    gettimeofday(&tv1, &tz);
    stats.finalcavityusec += usecelapsed(tv0, tv1);
#endif /* not NO_TIMER */
    
    /* keep track of lexmax cavity sizes */
    stats.finalcavitysizes[*numouttets]++;
    
    if (improvebehave.verbosity > 5)
    {
        printf("the lexmax cavity has %d tets, worst cavity qual = %g, worst deleted tet qual = %g:\n", *numouttets, pq(*worstincavity), pq(*worstdeleted));
    }
    
    /* print out the dag */
    /*
    printcavitydag(mesh, cavity, cavitysize);
    */
}

/* given a cavity of tets built around a single vertex,
   try to improve the cavity, and return the final quality */
starreal improvecavity(struct tetcomplex *mesh,
                       tag v,
                       tag tets[][4],
                       int numtets,
                       bool tryhard,
                       struct arraypoolstack *outstack,
                       starreal *shortest, starreal *longest)
{
    int i, stackiter=0;
    starreal quality;
    struct improvetet *stacktet;
    starreal smoothworst;
    starreal topoworst;
    starreal mean[NUMMEANTHRESHOLDS];
    starreal oldworst = 1.0;
    starreal newworst = 2.0;
    bool smoothed=true, toposuccess=true;
    tag newtet[4];
    int smoothkinds = 0;
    struct arraypoolstack stack[2];
    struct arraypoolstack influencestack;
    starreal physworst;
    
    /* change qual measure for insertion to consider edge length ratio */
    int qualmeasure = improvebehave.qualmeasure;
    
    int stacksize = 0;
    int maxstacksize = MAXCAVITYSTACK;
    int minimprovement = MINSUBMESHIMPROVEMENT;
    int maxpasses = MAXSUBMESHITERATIONS;
    
    if (improvebehave.facetsmooth) smoothkinds |= SMOOTHFACETVERTICES;
    if (improvebehave.segmentsmooth) smoothkinds |= SMOOTHSEGMENTVERTICES;
    if (improvebehave.fixedsmooth) smoothkinds |= SMOOTHFIXEDVERTICES;
    
    if (tryhard) 
    {
        maxstacksize *= TRYHARDFACTOR;
        minimprovement = TRYHARDMINSUBMESHIMPROVEMENT;
        maxpasses = TRYHARDMAXSUBMESHITERATIONS;
    }    
    
    /* longest and shortest edges of the affected tets */
    *longest = HUGEFLOAT;
    *shortest = 0.0;
    
    /* two stacks to keep track of all tets influenced by improvement */
    stackinit(&stack[0], sizeof(struct improvetet));
    stackinit(&stack[1], sizeof(struct improvetet));
    stackinit(&influencestack, sizeof(struct improvetet));
    
    /* initialize stack with all the cavity tets */
    for (i=0; i<numtets; i++)
    {
        /* compute tet quality */
        quality = tetquality(mesh, tets[i][0], tets[i][1], tets[i][2], tets[i][3], improvebehave.qualmeasure);
        if (quality < oldworst) oldworst = quality;
        
        /* push new tet on stack */
        stacktet = (struct improvetet *) stackpush(&stack[0]);
        stacktet->quality = quality;
        stacktet->verts[0] = tets[i][0];
        stacktet->verts[1] = tets[i][1];
        stacktet->verts[2] = tets[i][2];
        stacktet->verts[3] = tets[i][3];
    }
    
    /* iteratively try to improve cavity's worst quality */
    i = 0;
    while ((newworst > oldworst + minimprovement) && 
           (i <= maxpasses) && 
           (smoothed || toposuccess))
    {
        if (newworst != 2.0) oldworst = newworst;
        
        /* fetch a tet that the new vertex is in */
        findtetfromvertex(mesh, v, newtet);
        /* if the vertex no longer exists, stop improvemet */
        if (!tetexistsa(mesh, newtet))
        {
            break;
        }
        
        /* smooth new vertex */
        smoothed = nonsmoothsinglevertex(mesh,
                                         newtet[0],
                                         newtet[1],
                                         newtet[2],
                                         newtet[3],
                                         &smoothworst,
                                         smoothkinds);
        
        if (improvebehave.verbosity > 5)
        {
            printf("singlesmoothworst is %g\n, smoothed = %d", pq(smoothworst), smoothed);
        }
        
        /* improve cavity topology, alternating input/output stacks with bitwise XOR/AND */
        toposuccess = topopass(mesh, 
                               &stack[stackiter & 1], 
                               &stack[(stackiter & 1) ^ 1], 
                               qualmeasure, mean,
                               mean, &topoworst, true);
        stackiter++;
        
        if (improvebehave.sizing)
        {
            /* compute longest and shortest edge lengths for the output stack */
            longshortstack(mesh, &stack[stackiter & 1], longest, shortest);
        }
        
        if (improvebehave.verbosity > 5)
        {
            printf("topoworst is %g success = %d\n", pq(topoworst), toposuccess);
        }
        
        /* determine the new worst quality */
        if (toposuccess == false && smoothed == false && i == 0)
        {
            newworst = oldworst;
        }
        newworst = topoworst;
        
        if (improvebehave.verbosity > 5)
        {
            printf("Cavity improvement iter %d: %g -> %g\n", i, pq(oldworst), pq(newworst));
        }
        
        i++;
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("in the end, went through %d passes before smooth\n", i);
    }
    
    if (FINALCAVITYSMOOTH)
    {
        smoothed = true;
        while(stacksize < maxstacksize && i < maxpasses && smoothed)
        {
            /* at the end, try smoothing pass on all tets of cavity */
            smoothed = smoothpass(mesh, 
                                  &stack[i & 1], 
                                  &stack[(i & 1) ^ 1],
                                  &influencestack,
                                  improvebehave.qualmeasure,
                                  newworst, 
                                  mean,
                                  mean,
                                  &smoothworst,
                                  smoothkinds,
                                  true);
            stacksize = stack[(i & 1) ^ 1].top; 
            
            if (improvebehave.sizing)
            {
                /* compute longest and shortest edge lengths for the output stack */
                longshortstack(mesh, &stack[(i & 1) ^ 1], longest, shortest);
            }
            
            if (improvebehave.verbosity > 5)
            {
                printf("Performed smoothing pass %d (outstack size %d) on all verts, success = %d, %g -> %g\n", i, stacksize, smoothed, pq(newworst), pq(smoothworst));
            }
    
            if (smoothed && (smoothworst - newworst > minimprovement))
            {
                /* if the smoothing pass claims success, it had better have improved quality */
                assert(smoothworst > newworst);
                newworst = smoothworst;
            }
            else
            {
                if (improvebehave.verbosity > 5)
                {
                    printf("broke the loop, smoothed = %d, qualimprove = %g\n", smoothed, pq(smoothworst - newworst));
                }
                break;
            }
            i++;
        }
        
        if (stacksize >= maxstacksize && improvebehave.verbosity > 1)
        {
            printf("bailing because stacksize %d exceeded max %d\n", stacksize, maxstacksize);
        }
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("in the end, went through %d passes after final smooth\n", i);
    }
    
    /* if anisotropy is turned on, check for inverted tets in physical space */
    if (improvebehave.anisotropic)
    {
        improvebehave.anisotropic = false;
        /* if we did a final smooth */
        if (FINALCAVITYSMOOTH && influencestack.top != -1)
        {
            /* check the quality of this stack in physical space */
            physworst = worststackquality(mesh, &influencestack, improvebehave.qualmeasure);
        }
        else
        {
            /* check the quality of this stack in physical space */
            physworst = worststackquality(mesh, &stack[i & 1], improvebehave.qualmeasure);
        }
        improvebehave.anisotropic = true;
        
        if (improvebehave.verbosity > 0 && physworst <= 0.0)
        {
            printf("PHYSICAL worst quality after cavity improvement is %g\n", physworst);
        }
        assert(physworst > 0.0);
    }
    
    /* if there is a non-null output stack */
    if (outstack != NULL)
    {
        /* if we did a final smooth */
        if (FINALCAVITYSMOOTH && influencestack.top != -1)
        {
            /* return the entire influence stack */
            copystack(&influencestack, outstack);
            assert(outstack->top != -1);
        }
        else
        {
            /* just return output from last pass */
            copystack(&stack[i & 1], outstack);
            assert(outstack->top != -1);
        }
    }
    
    /* clean up stacks */
    stackdeinit(&stack[0]);
    stackdeinit(&stack[1]);
    stackdeinit(&influencestack);
    
    if (improvebehave.verbosity > 5)
    {
        printf("After cavity improvement, worst quality is %g\n", pq(newworst));
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("After cavity improvement, longest edge = %g, shortest = %g, goal = %g\n", *longest, *shortest, improvebehave.targetedgelength);
    }
    
    /* return the best we could do with this cavity */
    return newworst;
}

/* insert a new vertex in the facet specified, returning
   the new vertex tag, the new vertex position, and the 
   outward-oriented faces of the new tets */
bool facetinsert(struct tetcomplex *mesh,
                 tag v1,
                 tag v2,
                 tag v3,
                 tag v4,
                 tag face[3],
                 tag *vnew,
                 tag newfaces[][3],
                 int *numnewfaces,
                 tag newtets[][4],
                 int *numnewtets)
{
    struct vertex *newvertex;         /* pointer to newly allocated vertex */
    starreal *point[4];               /* actual vertices of the tet */
    starreal barycenter[3] = {0,0,0}; /* barycenter of input tet */
    tag tetverts[4];                  /* the vertices of the tet starting with the vert not on bound face */
    tag newtag;                       /* the tag of the newly inserted vertex */
    tag quadricfaces[3][3];
    tag journverts[1];
    struct quadric *quadrics[3];
    int i;
    bool quadsuccess;
    
    /* find which vertex is not part of the boundary face, and arrange tet
       vertices so first is the non-boundary-face vertex */
    if ((v1 != face[0]) && (v1 != face[1]) && (v1 != face[2]))
    {
        tetverts[0] = v1;
    }
    else
    {
        if ((v2 != face[0]) && (v2 != face[1]) && (v2 != face[2]))
        {
            tetverts[0] = v2;
        }
        else
        {
            if ((v3 != face[0]) && (v3 != face[1]) && (v3 != face[2]))
            {
                tetverts[0] = v3;
            }
            else
            {
                /* v4 must not be one of the face vertices */
                assert(((v4 != face[0]) && (v4 != face[1]) && (v4 != face[2])));
                tetverts[0] = v4;
            }
        }
    }
    
    /* the rest of the tet vertices should be the vertices of the boundary face, reversed in order
       so the face is oriented toward the fourth vertex */
    tetverts[1] = face[2];
    tetverts[2] = face[1];
    tetverts[3] = face[0];
    
    /* make sure our newly arranged tet exists */
    assert(tetexists(mesh, tetverts[0], tetverts[1], tetverts[2], tetverts[3]));
    
    /* fetch actual vertex values of face vertices */
    point[0] = ((struct vertex *) tetcomplextag2vertex(mesh, face[0]))->coord;
    point[1] = ((struct vertex *) tetcomplextag2vertex(mesh, face[1]))->coord;
    point[2] = ((struct vertex *) tetcomplextag2vertex(mesh, face[2]))->coord;
    
    /* fetch the ORIGINAL positions of the face vertices, because we want to start
       the vertex out on the original surface */
    quadrics[0] = (struct quadric *) arraypoolforcelookup(&surfacequadrics, face[0]);
    quadrics[1] = (struct quadric *) arraypoolforcelookup(&surfacequadrics, face[1]);
    quadrics[2] = (struct quadric *) arraypoolforcelookup(&surfacequadrics, face[2]);
    
    if (improvebehave.verbosity > 5)
    {
        printf("orig -> current face verts are:\n");
        for (i=0; i<3; i++)
        {
            printf("    (%g %g %g) -> (%g %g %g)\n", quadrics[i]->origpos[0], quadrics[i]->origpos[1], quadrics[i]->origpos[1], point[i][0], point[i][1], point[i][2]);
        }
    }
    
    /* compute barycenter of this face */
    vadd(barycenter, point[0], barycenter);
    vadd(barycenter, point[1], barycenter);
    vadd(barycenter, point[2], barycenter);
    /*
    vadd(barycenter, quadrics[0]->origpos, barycenter);
    vadd(barycenter, quadrics[1]->origpos, barycenter);
    vadd(barycenter, quadrics[2]->origpos, barycenter);
    */
    
    vscale(1.0 / 3.0, barycenter, barycenter);
    
    /* allocate a new vertex */
    newtag = proxipoolnew(mesh->vertexpool, 0, (void **) &newvertex);
    /* record this vertex insertion in the journal */
    journverts[0] = newtag;
    insertjournalentry(mesh, INSERTVERTEX, journverts, 1, NULL, barycenter);
    
    /* start the vertex at the face barycenter */
    vcopy(barycenter, newvertex->coord);
    
    /* delete the old tet and add the three new ones */
    flip13(mesh, tetverts[0], tetverts[1], tetverts[2], tetverts[3], newtag, true);
    /* make sure all the right tets exist now */
    assert(tetexists(mesh, tetverts[0], tetverts[1], newtag, tetverts[3]));
    assert(tetexists(mesh, tetverts[0], tetverts[2], newtag, tetverts[1]));
    assert(tetexists(mesh, tetverts[0], tetverts[3], newtag, tetverts[2]));
    
    /* assign the vertex type and compute the facet normal */
    tetvertexclassify(mesh,
                      newtag,
                      tetverts[0],
                      tetverts[1],
                      tetverts[3]);
    
    /* check that we got it right */
    /* this isn't necessarily true any more with quadrics */
    /*
    assert(((struct vertextype *) arraypoolforcelookup(&vertexinfo, newtag))->kind == FACETVERTEX);
    */
    
    /* initialize the quadric for this vertex */
    quadricfaces[0][0] = newtag;
    quadricfaces[0][1] = tetverts[2];
    quadricfaces[0][2] = tetverts[1];
    
    quadricfaces[1][0] = newtag;
    quadricfaces[1][1] = tetverts[3];
    quadricfaces[1][2] = tetverts[2];
    
    quadricfaces[2][0] = newtag;
    quadricfaces[2][1] = tetverts[1];
    quadricfaces[2][2] = tetverts[3];
    
    quadsuccess = addquadric(mesh, newtag, quadricfaces, 3);
    if (quadsuccess == false)
    {
        return false;
    }
    
    /* assign outputs */
    *vnew = newtag;
    
    *numnewtets = 3;
    newtets[0][0] = tetverts[0];
    newtets[0][1] = tetverts[1];
    newtets[0][2] = newtag;
    newtets[0][3] = tetverts[3];
    
    newtets[1][0] = tetverts[0];
    newtets[1][1] = tetverts[2];
    newtets[1][2] = newtag;
    newtets[1][3] = tetverts[1];
    
    newtets[2][0] = tetverts[0];
    newtets[2][1] = tetverts[3];
    newtets[2][2] = newtag;
    newtets[2][3] = tetverts[2];
    
    /* its possible that insertion fails outright because the vertices may have moved
       a lot due to smoothing from their original positions. so, check if any of the new
       tets are inverted, and return false if that's the case. */
    for (i=0; i<3; i++)
    {
        if (tetquality(mesh, 
                       newtets[i][0], 
                       newtets[i][1], 
                       newtets[i][2], 
                       newtets[i][3], 
                       improvebehave.qualmeasure) <= MINTETQUALITY)
        {
            if (improvebehave.verbosity > 1)
            {
                printf("Rejecting facet insertion because tet inverts.\n");
            }
            return false;
        }
        
        
    }
    
    *numnewfaces = 3;
    /* don't include outward faces on the boundary */
    /*
    newfaces[0][0] = newtag;
    newfaces[0][1] = tetverts[2];
    newfaces[0][2] = tetverts[1];
    
    newfaces[1][0] = newtag;
    newfaces[1][1] = tetverts[3];
    newfaces[1][2] = tetverts[2];
    
    newfaces[2][0] = newtag;
    newfaces[2][1] = tetverts[1];
    newfaces[2][2] = tetverts[3];
    */
    
    newfaces[0][0] = tetverts[0];
    newfaces[0][1] = tetverts[1];
    newfaces[0][2] = tetverts[2];
    
    newfaces[1][0] = tetverts[0];
    newfaces[1][1] = tetverts[3];
    newfaces[1][2] = tetverts[1];
    
    newfaces[2][0] = tetverts[0];
    newfaces[2][1] = tetverts[2];
    newfaces[2][2] = tetverts[3];
    
    return true;
}

void bodyinsert(struct tetcomplex *mesh,
                tag v1,
                tag v2,
                tag v3,
                tag v4,
                tag *vnew,
                tag newfaces[][3],
                int *numnewfaces,
                tag newtets[][4],
                int *numnewtets)
{
    tag newtag;                       /* the tag of the new vertex */
    struct vertex *newvertex;         /* pointer to newly allocated vertex */
    starreal *point[4];               /* actual vertices of the tet */
    starreal barycenter[3] = {0,0,0}; /* barycenter of input tet */
    int i;
    tag journverts[1];
    
    /* fetch actual vertex values of tet vertices */
    point[0] = ((struct vertex *) tetcomplextag2vertex(mesh, v1))->coord;
    point[1] = ((struct vertex *) tetcomplextag2vertex(mesh, v2))->coord;
    point[2] = ((struct vertex *) tetcomplextag2vertex(mesh, v3))->coord;
    point[3] = ((struct vertex *) tetcomplextag2vertex(mesh, v4))->coord;
    
    /* compute barycenter of this face */
    for (i=0; i<4; i++)
    {
        vadd(barycenter, point[i], barycenter);
    }
    vscale(0.25, barycenter, barycenter);
    
    /* allocate a new vertex */
    newtag = proxipoolnew(mesh->vertexpool, 0, (void **) &newvertex);
    /* record this vertex insertion in the journal */
    journverts[0] = newtag;
    insertjournalentry(mesh, INSERTVERTEX, journverts, 1, NULL, barycenter);
    
    /* start the vertex at the face barycenter */
    vcopy(barycenter, newvertex->coord);
    
    /* delete the old tet and add the three new ones */
    flip14(mesh, v1, v2, v3, v4, newtag, true);
    
    /* assign the vertex type */
    tetvertexclassify(mesh,
                      newtag,
                      v1,
                      v3,
                      v2);
    
    /* check that we got it right */
    assert(((struct vertextype *) arraypoolforcelookup(&vertexinfo, newtag))->kind == FREEVERTEX);
    
    /* assign outputs */
    *vnew = newtag;
    
    *numnewtets = 4;
    newtets[0][0] = v1;
    newtets[0][1] = v2;
    newtets[0][2] = v3;
    newtets[0][3] = newtag;
    
    newtets[1][0] = v1;
    newtets[1][1] = v3;
    newtets[1][2] = v4;
    newtets[1][3] = newtag;
    
    newtets[2][0] = v1;
    newtets[2][1] = v4;
    newtets[2][2] = v2;
    newtets[2][3] = newtag;
    
    newtets[3][0] = newtag;
    newtets[3][1] = v2;
    newtets[3][2] = v3;
    newtets[3][3] = v4;
    
    *numnewfaces = 4;
    newfaces[0][0] = v1;
    newfaces[0][1] = v2;
    newfaces[0][2] = v3;
    
    newfaces[1][0] = v1;
    newfaces[1][1] = v3;
    newfaces[1][2] = v4;
    
    newfaces[2][0] = v1;
    newfaces[2][1] = v4;
    newfaces[2][2] = v2;
    
    newfaces[3][0] = v2;
    newfaces[3][1] = v4;
    newfaces[3][2] = v3;
}

bool segmentinsert(struct tetcomplex *mesh,
                   tag v1,
                   tag v2,
                   tag v3,
                   tag v4,
                   int numtets,
                   tag tets[][4],
                   tag boundfaces[],
                   tag *vnew,
                   tag newfaces[][3],
                   int *numnewfaces,
                   tag newtets[][4],
                   int *numnewtets,
                   bool boundedge)
{
    tag newtag;                       /* the tag of the new vertex */
    struct vertex *newvertex;         /* pointer to newly allocated vertex */
    starreal *point[4];               /* actual vertices of the tet */
    starreal midpoint[3] = {0.,0.,0.};/* barycenter of boundary edge */
    tag splitedge[2];                 /* edge that will be split by insertion */
    tag quadricfaces[4][3];           /* four surface faces surrounding inserted vertex,
                                         used to initialize quadric */
    starreal qual;
    struct quadric *quadrics[2];
    
    int i;
    tag journverts[1];
    bool quadsuccess;
    
    /* all input tets should be arranged such that the edge we're splitting is made up
       of the first two vertices */
    
    /* pull out the edge that we'll be splitting */
    splitedge[0] = tets[0][0];
    splitedge[1] = tets[0][1];
    
    /* fetch actual vertex values of edge vertices */
    point[0] = ((struct vertex *) tetcomplextag2vertex(mesh, splitedge[0]))->coord;
    point[1] = ((struct vertex *) tetcomplextag2vertex(mesh, splitedge[1]))->coord;
    
    /* fetch the ORIGINAL positions of the edge vertices, because we want to start
       the vertex out on the original surface */
    quadrics[0] = (struct quadric *) arraypoolforcelookup(&surfacequadrics, splitedge[0]);
    quadrics[1] = (struct quadric *) arraypoolforcelookup(&surfacequadrics, splitedge[1]);
    
    if (improvebehave.verbosity > 5)
    {
        printf("Here is the original surface edge:\n");
        printf("[%g %g %g;\n", point[0][0], point[0][1], point[0][2]);
        printf("%g %g %g];\n", point[1][0], point[1][1], point[1][2]);
    }
    
    if (improvebehave.verbosity > 5)
    {
        printf("edge endpoints (%d %d) original positions (%g %g %g) and (%g %g %g)\n",
               (int) splitedge[0], (int) splitedge[1], quadrics[0]->origpos[0], quadrics[0]->origpos[1], quadrics[0]->origpos[2],
               quadrics[1]->origpos[0], quadrics[1]->origpos[1], quadrics[1]->origpos[2]);
    }
    
    /* compute midpoint of this edge */
    /* vadd(midpoint, quadrics[0]->origpos, midpoint);
    vadd(midpoint, quadrics[1]->origpos, midpoint); */
    vadd(midpoint, point[0], midpoint);
    vadd(midpoint, point[1], midpoint);
    vscale(0.5, midpoint, midpoint);
    
    /* allocate a new vertex */
    newtag = proxipoolnew(mesh->vertexpool, 0, (void **) &newvertex);
    /* record this vertex insertion in the journal */
    journverts[0] = newtag;
    insertjournalentry(mesh, INSERTVERTEX, journverts, 1, NULL, midpoint);
    
    /* start the vertex at the edge midpoint */
    vcopy(midpoint, newvertex->coord);
    
    *numnewfaces = 0;
    *numnewtets = 0;
    *vnew = newtag;
    
    /* for every tet that surrounds this edge, perform a 1-2 flip */
    for (i=0; i<numtets; i++)
    {
        /* make sure the first two verts of this tet are the edge to be split */
        assert((tets[i][0] == splitedge[0] && tets[i][1] == splitedge[1]) ||
               (tets[i][0] == splitedge[1] && tets[i][1] == splitedge[0]));
        
        /* make sure the old tet exists */
        assert(tetexists(mesh, tets[i][0], tets[i][1], tets[i][2], tets[i][3]));
        
        /* delete the old tet and add the two new ones */
        flip12(mesh, tets[i][0], tets[i][1], tets[i][2], tets[i][3], newtag, true);
        
        /* make sure all the right tets exist now */
        assert(tetexists(mesh, tets[i][0], tets[i][2], tets[i][3], newtag));
        assert(tetexists(mesh, tets[i][1], tets[i][3], tets[i][2], newtag));
        
        /* add these tets to the output */
        newtets[*numnewtets][0] = tets[i][0];
        newtets[*numnewtets][1] = tets[i][2];
        newtets[*numnewtets][2] = tets[i][3];
        newtets[*numnewtets][3] = newtag;
        
        /* if anisotropy, check if this tet is inverted in PHYSICAL SPACE */
        if (improvebehave.anisotropic)
        {
            improvebehave.anisotropic = false;
            qual = tetquality(mesh,
                           newtets[*numnewtets][0],
                           newtets[*numnewtets][1],
                           newtets[*numnewtets][2],
                           newtets[*numnewtets][3],
                           improvebehave.qualmeasure); 
            improvebehave.anisotropic = true;
            
            if (qual <= MINSIZETETQUALITY)
            {
                if (improvebehave.verbosity > 1)
                {
                    printf("rejecting segment insert because tet would invert in PHYSICAL SPACE\n");
                }
                return false;
            }
        }
        
        /* if this tet is inverted, give up */
        qual = tetquality(mesh,
                       newtets[*numnewtets][0],
                       newtets[*numnewtets][1],
                       newtets[*numnewtets][2],
                       newtets[*numnewtets][3],
                       improvebehave.qualmeasure); 
        if (improvebehave.verbosity > 5)
        {
            printf("New tet (%d %d %d %d) has quality %g\n", (int) newtets[*numnewtets][0],
                                                             (int) newtets[*numnewtets][1],
                                                             (int) newtets[*numnewtets][2],
                                                             (int) newtets[*numnewtets][3],
                                                             qual);
        }
        
        if (qual <= MINTETQUALITY)
        {
            if (improvebehave.verbosity > 1)
            {
                printf("rejecting segment insert because tet would invert\n");
            }
            return false;
        }
        
        (*numnewtets)++;
        
        newtets[*numnewtets][0] = tets[i][1];
        newtets[*numnewtets][1] = tets[i][3];
        newtets[*numnewtets][2] = tets[i][2];
        newtets[*numnewtets][3] = newtag;
        
        /* if anisotropy, check if this tet is inverted in PHYSICAL SPACE */
        if (improvebehave.anisotropic)
        {
            improvebehave.anisotropic = false;
            qual = tetquality(mesh,
                           newtets[*numnewtets][0],
                           newtets[*numnewtets][1],
                           newtets[*numnewtets][2],
                           newtets[*numnewtets][3],
                           improvebehave.qualmeasure); 
            improvebehave.anisotropic = true;
            
            if (qual <= MINSIZETETQUALITY)
            {
                if (improvebehave.verbosity > 1)
                {
                    printf("rejecting segment insert because tet would invert in PHYSICAL SPACE\n");
                }
                return false;
            }
        }
        
        qual = tetquality(mesh,
                       newtets[*numnewtets][0],
                       newtets[*numnewtets][1],
                       newtets[*numnewtets][2],
                       newtets[*numnewtets][3],
                       improvebehave.qualmeasure); 
        if (improvebehave.verbosity > 5)
        {
            printf("New tet (%d %d %d %d) has quality %g\n", (int) newtets[*numnewtets][0],
                                                             (int) newtets[*numnewtets][1],
                                                             (int) newtets[*numnewtets][2],
                                                             (int) newtets[*numnewtets][3],
                                                             qual);
        }
        
        if (qual <= MINTETQUALITY)
        {
            if (improvebehave.verbosity > 1)
            {
                printf("rejecting segment insert because tet would invert\n");
            }
            return false;
        }
        
        (*numnewtets)++;
        
        /* add the "external" faces of the new tets to the output */
        newfaces[*numnewfaces][0] = tets[i][0];
        newfaces[*numnewfaces][1] = tets[i][2];
        newfaces[*numnewfaces][2] = tets[i][3];
        (*numnewfaces)++;
        
        newfaces[*numnewfaces][0] = tets[i][1];
        newfaces[*numnewfaces][1] = tets[i][3];
        newfaces[*numnewfaces][2] = tets[i][2];
        (*numnewfaces)++;
    }
    
    /* check if any of the new tets are inverted, and return false if so */
    
    /* add the last four faces of the split boundary faces to output */
    /* actually, exclude these faces because they lie on the boundary */
    /*
    newfaces[*numnewfaces][0] = newtag;
    newfaces[*numnewfaces][1] = splitedge[1];
    newfaces[*numnewfaces][2] = boundfaces[0];
    (*numnewfaces)++;
    
    newfaces[*numnewfaces][0] = newtag;
    newfaces[*numnewfaces][1] = boundfaces[0];
    newfaces[*numnewfaces][2] = splitedge[0];
    (*numnewfaces)++;
    
    newfaces[*numnewfaces][0] = newtag;
    newfaces[*numnewfaces][1] = boundfaces[1];
    newfaces[*numnewfaces][2] = splitedge[1];
    (*numnewfaces)++;
    
    newfaces[*numnewfaces][0] = newtag;
    newfaces[*numnewfaces][1] = splitedge[0];
    newfaces[*numnewfaces][2] = boundfaces[1];
    (*numnewfaces)++;
    */
    
    /*
    tag outin[2];
    bool foundface;
    foundface = tetcomplexadjacencies(mesh, newtag, splitedge[1], boundfaces[0], outin);
    assert(foundface);
    printf("(new, edge[1], bf[0]: out = %d, in = %d\n", outin[0], outin[1]);
    foundface = tetcomplexadjacencies(mesh, newtag, boundfaces[0], splitedge[0], outin);
    assert(foundface);
    printf("(new, bf[0], edge[0]: out = %d, in = %d\n", outin[0], outin[1]);
    foundface = tetcomplexadjacencies(mesh, newtag, boundfaces[1], splitedge[1], outin);
    assert(foundface);
    printf("(new, bf[1], edge[1]: out = %d, in = %d\n", outin[0], outin[1]);
    foundface = tetcomplexadjacencies(mesh, newtag, splitedge[0], boundfaces[1], outin);
    assert(foundface);
    printf("(new, edge[0], bf[1]: out = %d, in = %d\n", outin[0], outin[1]);
    */
    
    /* initialize the quadric for this vertex */
    if (boundedge)
    {
        quadricfaces[0][0] = newtag;
        quadricfaces[0][1] = splitedge[1];
        quadricfaces[0][2] = boundfaces[0];
        quadricfaces[1][0] = newtag;
        quadricfaces[1][1] = boundfaces[0];
        quadricfaces[1][2] = splitedge[0];
        quadricfaces[2][0] = newtag;
        quadricfaces[2][1] = boundfaces[1];
        quadricfaces[2][2] = splitedge[1];
        quadricfaces[3][0] = newtag;
        quadricfaces[3][1] = splitedge[0];
        quadricfaces[3][2] = boundfaces[1];
        quadsuccess = addquadric(mesh, newtag, quadricfaces, 4);
        if (quadsuccess == false)
        {
            if (improvebehave.verbosity > 0)
            {
                printf("segment insertion failed because adding the quadric failed.\n");
            }
            return false;
        }
    }
    
    /* assign the vertex type and compute the facet normal */
    tetvertexclassify(mesh,
                      newtag,
                      tets[0][1],
                      tets[0][2],
                      tets[0][3]);
    
    /* check that we got it right; new vertex can either be segment or facet vertex */
    /* this is no longer necessarily true because of quadric smoothing */
    /*
    assert((((struct vertextype *) arraypoolforcelookup(&vertexinfo, newtag))->kind == SEGMENTVERTEX) ||
           (((struct vertextype *) arraypoolforcelookup(&vertexinfo, newtag))->kind == FACETVERTEX));
    */
    return true;
}

/* general vertex insertion routine */
bool insertvertex(struct tetcomplex *mesh,
                  tag v1,
                  tag v2,
                  tag v3,
                  tag v4,
                  starreal inquality,
                  starreal meshworstquality,
                  starreal *outquality,
                  struct arraypoolstack *outstack,
                  bool tryhard)
{
    int nbverts, nbedges, nbfaces; /* number of boundary components */
    tag boundtags[4];              /* boundary vertex tags */
    tag boundfacetags[4][3];       /* boundary face tags */
    tag boundedgetags[6][2];       /* boundary edge tags */
    tag boundedgefaces[6][2];      /* the third vertices of the faces in the ring around an edge that lie on the boundary */
    int numboundedgetets[6];       /* number of tets in ring around each boundary edge */
    tag boundedgetets[6][MAXRINGTETS][4]; /* the list of the tets in the ring around each edge */
    bool bfaces;
    
    tag vnew;                      /* newly inserted vertex tag */
    static tag newfaces[MAXCAVITYFACES][3]; /* faces of tets created after insert for seeding cavity drilling */
    int numnewfaces;               
    static tag newtets[MAXCAVITYTETS][4]; /* tets that filled in cavity */
    int numnewtets;
    starreal minquality;           /* quality we have to beat for inserion to succeed */
    starreal origcavityqual;       /* quality of the worst tet in the cavity */
    starreal worstdeletedqual;     /* quality of the worst tet deleted to form the cavity */
    starreal cavityqual;           /* quality of the improved cavity */
    starreal longest, shortest;    /* shortest and longest edges in a cavity */
    bool success;
    bool sizeok;
    
    struct arraypoolstack cavitystack; /* save the tets affected by cavity improvement */
    struct arraypoolstack *cavitystackptr; /* may be null if outstack is null */
    
#ifndef NO_TIMER
    struct timeval tv0, tv1;
    struct timezone tz;
#endif /* not NO_TIMER */

    int i;
    
    /* remember the last journal entry before we change anything */
    int beforeid = lastjournalentry(); 
    
    /* make sure this tet still exists */
    if (tetexists(mesh, v1, v2, v3, v4) == false) return false;
    
    if (improvebehave.verbosity > 5)
    {
        printf("Attempting general vertex insertion on tet (%d %d %d %d)\n", (int) v1, (int) v2, (int) v3, (int) v4);
        printtetvertssep(mesh, v1, v2, v3, v4);
    }
    
    /* start by gathering boundary information on this tet */
    nbverts = boundverts(mesh, v1, v2, v3, v4, boundtags);
    nbedges = boundedges(mesh, v1, v2, v3, v4, boundedgetags, 
                                               boundedgefaces,
                                               numboundedgetets,
                                               boundedgetets);
    bfaces = boundfaces(mesh, v1, v2, v3, v4,  boundfacetags, &nbfaces);
    
    /* initialize cavity stack */
    stackinit(&cavitystack, sizeof(struct improvetet));
    if (outstack == NULL)
    {
        cavitystackptr = NULL;
    }
    else
    {
        cavitystackptr = &cavitystack;
    }
    
    /*************************************/
    /********** FACET INSERTION **********/
    /*************************************/
    /* if the tet has any boundary faces, try insertion on them first */
    /* TODO: why? */
    if (improvebehave.insertfacet)
    {
        for (i=0; i<nbfaces; i++)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("Attempting facet insertion...\n");
            }
            
            /* stats */
            stats.facetinsertattempts++;
            
            /* perform the initial insertion using a 1-3 flip, locating the new
               vertex at the barycenter of the facet */
            success = facetinsert(mesh, v1, v2, v3, v4, 
                        boundfacetags[i], 
                        &vnew, 
                        newfaces, &numnewfaces,
                        newtets, &numnewtets);
            
            /* if one of the new tets is inverted, give up */
            if (success == false)
            {
                invertjournalupto(mesh, beforeid);
                continue;
            }
            
            /* dig out optimal cavity */
            optimalcavity(mesh, vnew,
                        newtets, numnewtets, 
                        newfaces, numnewfaces, 
                        newtets, &numnewtets,
                        &worstdeletedqual,
                        &origcavityqual, true);
                    
            if (improvebehave.verbosity > 5)
            {
                printf("The quality of the split tet was %g vs worst deleted to form cavity of %g\n", pq(inquality), pq(worstdeletedqual));
            }
        
            /* the quality we have to beat when improving the cavity is the
               worst of the split tet and those of the dug-out cavity */
            minquality = (worstdeletedqual < inquality) ? worstdeletedqual : inquality;
        
            if (improvebehave.verbosity > 5)
            {
                printf("Here is the cavity returned (it has %d tets):\n", numnewtets);
                printtets(mesh, newtets, numnewtets);
            }
        
            /* improve the cavity */
#ifndef NO_TIMER
            gettimeofday(&tv0, &tz);
#endif /* not NO_TIMER */
            cavityqual = improvecavity(mesh, vnew, newtets, numnewtets, tryhard, cavitystackptr, &longest, &shortest);
#ifndef NO_TIMER            
            gettimeofday(&tv1, &tz);
            stats.cavityimproveusec += usecelapsed(tv0, tv1);
#endif
            
            if ( improvebehave.sizing &&
                 ((longest > improvebehave.targetedgelength * improvebehave.longerfactor) ||
                 (shortest < improvebehave.targetedgelength * improvebehave.shorterfactor))
               )
            {
                if (improvebehave.verbosity > 3)
                {
                    printf("Aborting insertion because it would create bad edge of length %g/%g, target is %g\n", longest, shortest, improvebehave.targetedgelength);
                }
                sizeok = false;
            }
            else
            {
                sizeok = true;
            }
            
            /* did we succeed? */
            if (cavityqual > (minquality + MININSERTIONIMPROVEMENT) && sizeok)
            {
                /* yes. keep the insertion */
                if (improvebehave.verbosity > 4)
                {
                    printf("Facet vertex insertion succeeded. minqual = %g, cavityqual = %g\n", pq(minquality), pq(cavityqual));
                }
                
                /* add the affected tets to the output stack */
                if (outstack != NULL)
                {
                    appendstack(&cavitystack, outstack);
                }
                stackdeinit(&cavitystack);
                
                /* stats */
                stats.facetinsertsuccesses++;
                *outquality = cavityqual;
                return true;
            }
            else
            {
                /* no. reverse the damage */
                if (improvebehave.verbosity > 5)
                {
                    printf("Facet vertex insertion failed. minqual = %g, cavityqual = %g\n", pq(minquality), pq(cavityqual));
                }
            
                invertjournalupto(mesh, beforeid);
            }
        }
    }
    
    /*************************************/
    /********** BODY INSERTION ***********/
    /*************************************/
    if (improvebehave.insertbody)
    {
        if (improvebehave.verbosity > 5)
        {
            printf("Attempting bady insertion...\n");
        }
        
        /* stats */
        stats.bodyinsertattempts++;
        
        /* perform the initial insertion using a 1-4 flip, locating the new
           vertex at the barycenter of the tet */
        bodyinsert(mesh, v1, v2, v3, v4,
                   &vnew, 
                   newfaces, &numnewfaces,
                   newtets, &numnewtets);
    
        /* dig out optimal cavity */
        optimalcavity(mesh, vnew,
                    newtets, numnewtets, 
                    newfaces, numnewfaces, 
                    newtets, &numnewtets,
                    &worstdeletedqual,
                    &origcavityqual, true);
                
        if (improvebehave.verbosity > 5)
        {
            printf("The quality of the split tet was %g vs worst deleted to form cavity of %g\n", pq(inquality), pq(worstdeletedqual));
        }
    
        /* the quality we have to beat when improving the cavity is the
           worst of the split tet and those of the dug-out cavity */
        minquality = (worstdeletedqual < inquality) ? worstdeletedqual : inquality;
    
        if (improvebehave.verbosity > 5)
        {
            printf("Here is the cavity returned (it has %d tets):\n", numnewtets);
            printtets(mesh, newtets, numnewtets);
        }
    
        /* improve the cavity */
#ifndef NO_TIMER
        gettimeofday(&tv0, &tz);
#endif /* not NO_TIMER */
        cavityqual = improvecavity(mesh, vnew, newtets, numnewtets, tryhard, cavitystackptr, &longest, &shortest);
#ifndef NO_TIMER
        gettimeofday(&tv1, &tz);
        stats.cavityimproveusec += usecelapsed(tv0, tv1);
#endif /* not NO_TIMER */

        if ( improvebehave.sizing &&
             ((longest > improvebehave.targetedgelength * improvebehave.longerfactor) ||
             (shortest < improvebehave.targetedgelength * improvebehave.shorterfactor))
           )
        {
            if (improvebehave.verbosity > 3)
            {
                printf("Aborting insertion because it would create bad edge of length %g/%g, target is %g\n", longest, shortest, improvebehave.targetedgelength);
            }
            sizeok = false;
        }
        else
        {
            sizeok = true;
        }
        
        /* did we succeed? */
        if (cavityqual > (minquality + MININSERTIONIMPROVEMENT) && sizeok)
        {
            /* yes. keep the insertion */
            if (improvebehave.verbosity > 4)
            {
                printf("Body vertex insertion succeeded. minqual = %g, cavityqual = %g\n", pq(minquality), pq(cavityqual));
                if (cavitystackptr != NULL)
                {
                    printf("    and by the way, the worst stack quality is %g\n", worststackquality(mesh,cavitystackptr,improvebehave.qualmeasure));
                }
            }
            
            /* add the affected tets to the output stack */
            if (outstack != NULL)
            {
                appendstack(&cavitystack, outstack);
            }
            stackdeinit(&cavitystack);
            
            /* stats */
            stats.bodyinsertsuccesses++;
            *outquality = cavityqual;
            return true;
        }
        else
        {
            /* no. reverse the damage */
            if (improvebehave.verbosity > 5)
            {
                printf("Body vertex insertion failed. minqual = %g, cavityqual = %g\n", pq(minquality), pq(cavityqual));
            }
        
            invertjournalupto(mesh, beforeid);
        }
    }
    
    /*************************************/
    /******** SEGMENT INSERTION **********/
    /*************************************/
    if (improvebehave.insertsegment)
    {
        for (i=0; i<nbedges; i++)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("Attempting segment insertion...\n");
            }
            
            /* stats */
            stats.segmentinsertattempts++;
            
            /* perform initial vertex insertion */
            success = segmentinsert(mesh, v1, v2, v3, v4, 
                          numboundedgetets[i], boundedgetets[i],
                          boundedgefaces[i],
                          &vnew, 
                          newfaces, &numnewfaces,
                          newtets, &numnewtets, true);
            
            /* if one of the new tets is inverted, give up */
            if (success == false)
            {
                invertjournalupto(mesh, beforeid);
                continue;
            }
            
            if (improvebehave.verbosity > 5)
            {
                printf("segment insertion returned this set of split tets:\n");
                printtets(mesh, newtets, numnewtets);
            }
            
            /* dig out optimal cavity */
            optimalcavity(mesh, vnew,
                        newtets, numnewtets, 
                        newfaces, numnewfaces, 
                        newtets, &numnewtets,
                        &worstdeletedqual,
                        &origcavityqual, true);
                    
            if (improvebehave.verbosity > 5)
            {
                printf("The quality of the split tet was %g vs worst deleted to form cavity of %g\n", pq(inquality), pq(worstdeletedqual));
            }
        
            /* the quality we have to beat when improving the cavity is the
               worst of the split tet and those of the dug-out cavity */
            minquality = (worstdeletedqual < inquality) ? worstdeletedqual : inquality;
        
            if (improvebehave.verbosity > 5)
            {
                printf("Here is the cavity returned (it has %d tets):\n", numnewtets);
                printtets(mesh, newtets, numnewtets);
            }
            
            /* improve the cavity */
#ifndef NO_TIMER
            gettimeofday(&tv0, &tz);
#endif /* not NO_TIMER */
            cavityqual = improvecavity(mesh, vnew, newtets, numnewtets, tryhard, cavitystackptr, &longest, &shortest);
#ifndef NO_TIMER
            gettimeofday(&tv1, &tz);
            stats.cavityimproveusec += usecelapsed(tv0, tv1);
#endif /* not NO_TIMER */
            
            if ( improvebehave.sizing &&
                 ((longest > improvebehave.targetedgelength * improvebehave.longerfactor) ||
                 (shortest < improvebehave.targetedgelength * improvebehave.shorterfactor))
               )
            {
                if (improvebehave.verbosity > 3)
                {
                    printf("Aborting insertion because it would create bad edge of length %g/%g, target is %g\n", longest, shortest, improvebehave.targetedgelength);
                }
                sizeok = false;
            }
            else
            {
                sizeok = true;
            }
            
            /* did we succeed? */
            if (cavityqual > (minquality + MININSERTIONIMPROVEMENT) && sizeok)
            {
                /* yes. keep the insertion */
                if (improvebehave.verbosity > 4)
                {
                    printf("Segment vertex insertion succeeded. minqual = %g, cavityqual = %g\n", pq(minquality), pq(cavityqual));
                }
                
                /* add the affected tets to the output stack */
                if (outstack != NULL)
                {
                    appendstack(&cavitystack, outstack);
                }
                stackdeinit(&cavitystack);
                
                /* stats */
                stats.segmentinsertsuccesses++;
                *outquality = cavityqual;
                return true;
            }
            else
            {
                /* no. reverse the damage */
                if (improvebehave.verbosity > 5)
                {
                    printf("Segment vertex insertion failed. minqual = %g, cavityqual = %g\n", pq(minquality), pq(cavityqual));
                }
            
                invertjournalupto(mesh, beforeid);
            }
        }
    }
    
    stackdeinit(&cavitystack);
    return false;
}

/* attempt insertion on a stack of tets */
bool insertpass(struct tetcomplex *mesh,
                struct arraypoolstack *tetstack,
                struct arraypoolstack *outstack,
                int qualmeasure,
                starreal meanqualafter[],
                starreal *minqualafter,
                starreal okayqual,
                bool quiet)
{
    struct improvetet *stacktet;
    bool success = false;
    starreal minqualbefore;
    starreal meanqualbefore[NUMMEANTHRESHOLDS];
    int attempts=0;
    int inserts=0;
    starreal cavityqual;
    starreal meshworstqual;
    bool tryhard = false;
    int beforeid = lastjournalentry();
    
    int origstacksize = tetstack->top + 1;
    
    /* reset output stack */
    if (outstack != NULL)
    {
        /* copy the input stack to output stack */
        stackrestart(outstack);
        copystack(tetstack, outstack);
    }
    
    /* get global worst for paranoid insertion */
    meshworstqual = HUGEFLOAT;
    if (INSERTPARANOID)
    {
        meshquality(mesh, qualmeasure, meanqualbefore, &meshworstqual);
    }
    
    /* compute worst input quality. do it global if no output stack */
    if (outstack != NULL)
    {
        stackquality(mesh, tetstack, qualmeasure, meanqualbefore, &minqualbefore);
    }
    else
    {
        meshquality(mesh, qualmeasure, meanqualbefore, &minqualbefore);
    }
    
    /* now go through the stack collecting information */
    while (tetstack->top != STACKEMPTY)
    {
        if (improvebehave.verbosity > 4 && (tetstack->top % 20 == 0))
        {
            textcolor(BRIGHT, MAGENTA, BLACK);
            printf("%ld remaining tets\r\n", tetstack->top);
            textcolor(RESET, WHITE, BLACK);
        }
        
        /* pull the top tet off the stack */
        stacktet = (struct improvetet *) stackpop(tetstack);
        
        /* make sure this tet still exists */
        if (tetexists(mesh,
                      stacktet->verts[0],
                      stacktet->verts[1],
                      stacktet->verts[2],
                      stacktet->verts[3]) == false) continue;
        
        /* because this tet might have been fixed up in a previous insertion,
           recompute its quality */
        stacktet->quality = tetquality(mesh, 
                                       stacktet->verts[0],
                                       stacktet->verts[1], 
                                       stacktet->verts[2], 
                                       stacktet->verts[3],
                                       improvebehave.qualmeasure);
        
        /* if this tet is already above the demanded quality, don't attempt insertion */
        if (stacktet->quality >= okayqual && okayqual > 0.0)
        {
            if (improvebehave.verbosity > 5)
            {
                printf("skipping insertion attempt because tet quality %g is better than %g\n", pq(stacktet->quality), pq(okayqual));
            }
            continue;
        }
        
        /* determine if we should try extra hard for this insertion to work out */
        if (okayqual > 0.0 || stacktet->quality - minqualbefore < CLOSETOWORST)
        {
            tryhard = true;
        }
        else
        {
            tryhard = false;
        }
        
        /* attempt to insert a vertex */
        success = insertvertex(mesh,
                               stacktet->verts[0],
                               stacktet->verts[1], 
                               stacktet->verts[2], 
                               stacktet->verts[3],
                               stacktet->quality,
                               minqualbefore,
                               &cavityqual,
                               outstack,
                               tryhard);
        attempts++;
        inserts += success ? 1 : 0;
        
        if (INSERTPARANOID)
        {
            starreal newworst, newmean[NUMMEANTHRESHOLDS];
            meshquality(mesh, qualmeasure, newmean, &newworst);
            if (success == false)
            {
                if (meshworstqual != newworst)
                {
                    printf("meshworstqual = %g, newworst = %g\n", pq(meshworstqual), pq(newworst));
                }
                assert(meshworstqual == newworst);
            }
            else
            {
                if (newworst < meshworstqual)
                {
                    printf("uhoh... worst qual went from %g to %g (diff = %g) on success...\n", pq(meshworstqual), pq(newworst), pq(newworst - meshworstqual));
                    printjournaltop(5);
                    worsttetreport(mesh, improvebehave.qualmeasure, 1.0);
                }
                assert(newworst >= meshworstqual);
                meshworstqual = newworst;
            }
        }
        
        success = false;
    }
    
    if (outstack != NULL)
    {
        stackquality(mesh, outstack, qualmeasure, meanqualafter, minqualafter);
        if (improvebehave.verbosity > 1)
        {
            printf("just completed insertion improvment pass.\n");
            printf("    input stack had %d tets\n", origstacksize);
            printf("    output stack had %lu tets\n", outstack->top+1);
            printf("    claimed input quality is            %g\n", pq(minqualbefore));
            printf("    worst quality in the output stack is %g\n", pq(*minqualafter));
            printf("    Insertion successes / attempts: %d/%d\n", inserts, attempts);
        }
        
        /* if the worst quality didn't improve on insertion, undo this insertion pass */
        if (*minqualafter < minqualbefore || (*minqualafter == minqualbefore && inserts == 0))
        {
            if (improvebehave.verbosity > 1)
            {
                printf("Undoing last insertion pass, minqualbefore was %g but after was %g\n", minqualbefore, *minqualafter);
            }
            invertjournalupto(mesh, beforeid);
            
            /* reset minimum output quality */
            *minqualafter = minqualbefore;
            
            return false;
        }
    }
    
    if (improvebehave.verbosity > 4)
    {
        printf("Insertion successes / attempts: %d/%d\n", inserts, attempts);
    }
    
    if (inserts > 0) return true;
    
    return false;
}


/* go after the worst tets. with insertion */
void worsttetattack(struct tetcomplex *mesh,
                    int qualmeasure,
                    starreal percentinsert,
                    starreal outmeanqual[],
                    starreal *outminqual,
                    bool desperate)
{
    starreal minqual, meanqual[NUMMEANTHRESHOLDS];/* quality of the worst tet in the mesh */
    struct arraypoolstack tetstack;      /* stack of tets  */
    starreal meshworstqual, origmeshworstqual;
    starreal fillthresh;
    
    /* initialize the tet stack */
    stackinit(&tetstack, sizeof(struct improvetet));
    
    meshquality(mesh, qualmeasure, meanqual, &minqual);
    
    if (desperate == false)
    {    
        /* fill the stack of with the worst percent insert tets */
        fillstackpercent(mesh, &tetstack, qualmeasure, percentinsert, meanqual, &minqual);
        if (improvebehave.verbosity > 4)
        {
            textcolor(BRIGHT, MAGENTA, BLACK);
            printf("Attempting vertex insertion on the worst %g percent of tets (%ld).\n", percentinsert * 100.0, tetstack.top);
            textcolor(RESET, WHITE, BLACK);
        }
    }
    else
    {
        if (minqual + QUALFROMDESPERATE < improvebehave.maxinsertquality[improvebehave.qualmeasure])
        {
            fillthresh = minqual + QUALFROMDESPERATE;
        }
        else if (minqual > improvebehave.maxinsertquality[improvebehave.qualmeasure])
        {
            fillthresh = minqual + QUALUPFROMDESPERATE;
        }
        else
        {
            fillthresh = improvebehave.maxinsertquality[improvebehave.qualmeasure];
        }
        fillstackqual(mesh, &tetstack, qualmeasure, fillthresh, meanqual, &minqual);
        if (improvebehave.verbosity > 4)
        {
            textcolor(BRIGHT, MAGENTA, BLACK);
            printf("Attempting DESPERATE vertex insertion on the %ld tets with qual less than %g (%g degrees).\n", tetstack.top, fillthresh, pq(fillthresh));
            textcolor(RESET, WHITE, BLACK);
        }
    }
    
    origmeshworstqual = meshworstqual = minqual;
    
    /* perform insertion pass on stack of tets */
    insertpass(mesh, &tetstack, NULL, qualmeasure, NULL, outminqual, -1.0, false);
    
    /* free the stack of tets */
    stackdeinit(&tetstack);
    
    meshquality(mesh, qualmeasure, outmeanqual, outminqual);
    
    if (!improvebehave.fixedsmooth) 
    {
        if (*outminqual < origmeshworstqual)
        {
            printf("crap, mesh min qual = %g after insert pass, %g before.\n", pq(*outminqual), pq(origmeshworstqual));
        }
        assert(*outminqual >= origmeshworstqual);
    }
    
    /* print report */
    if (improvebehave.verbosity > 3)
    {
        if (meshworstqual > origmeshworstqual)
        {
            textcolor(BRIGHT, GREEN, BLACK);
            printf("    Worst angle in mesh improved from %g to %g degrees\n", pq(origmeshworstqual), pq(meshworstqual));
            textcolor(RESET, WHITE, BLACK);
        }
    }
}















<|start_filename|>vtkVmtk/IO/vtkvmtkTetGenWriter.h<|end_filename|>
/*=========================================================================
                                                                                                                                    
Program:   VMTK
Module:    $RCSfile: vtkvmtkTetGenWriter.h,v $
Language:  C++
Date:      $Date: 2006/04/06 16:47:47 $
Version:   $Revision: 1.2 $
                                                                                                                                    
  Copyright (c) <NAME>, <NAME>. All rights reserved.
  See LICENSE file for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm 
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.
                                                                                                                                    
=========================================================================*/
// .NAME vtkvmtkTetGenWriter - writes TetGen .msh files.
// .SECTION Description
// vtkvmtkTetGenWriter writes TetGen .msh files. Many thanks to <NAME>, <NAME> and <NAME>, BioFluids Laboratory, Stony Brook University, Stony Brook, NY, for the inputs on the file format.
//
// .SECTION See Also

#ifndef __vtkvmtkTetGenWriter_h
#define __vtkvmtkTetGenWriter_h

#include "vtkvmtkWin32Header.h"
#include "vtkUnstructuredGridWriter.h"

class vtkCell;
class vtkIdList;

class VTK_VMTK_IO_EXPORT vtkvmtkTetGenWriter : public vtkUnstructuredGridWriter
{
public:
  static vtkvmtkTetGenWriter *New();
  vtkTypeMacro(vtkvmtkTetGenWriter,vtkUnstructuredGridWriter);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE;

  vtkSetStringMacro(BoundaryDataArrayName);
  vtkGetStringMacro(BoundaryDataArrayName);

protected:
  vtkvmtkTetGenWriter();
  ~vtkvmtkTetGenWriter();

  void ConvertFaceToLeftHanded(vtkUnstructuredGrid* input, vtkIdType tetraCellId, vtkIdType& id0, vtkIdType& id1, vtkIdType& id2);

  void WriteData() VTK_OVERRIDE;

  char* BoundaryDataArrayName;

private:
  vtkvmtkTetGenWriter(const vtkvmtkTetGenWriter&);  // Not implemented.
  void operator=(const vtkvmtkTetGenWriter&);  // Not implemented.
};

#endif
